Merge pull request #221 from GetStream/hotfix/qa5.1

Hotfix/qa5.1
This commit is contained in:
Salvatore Giordano
2021-01-19 11:25:31 +01:00
committed by GitHub
6 changed files with 334 additions and 303 deletions
@@ -14,6 +14,8 @@ class ChannelBottomSheet extends StatefulWidget {
} }
class _ChannelBottomSheetState extends State<ChannelBottomSheet> { class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
bool _showActions = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var channel = StreamChannel.of(context).channel; var channel = StreamChannel.of(context).channel;
@@ -33,157 +35,177 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
topRight: Radius.circular(16.0), topRight: Radius.circular(16.0),
), ),
), ),
child: ListView( child: !_showActions
shrinkWrap: true, ? SizedBox()
children: [ : ListView(
SizedBox( shrinkWrap: true,
height: 24.0,
),
Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: ChannelName(
textStyle: StreamChatTheme.of(context).textTheme.headlineBold,
),
),
),
SizedBox(
height: 5.0,
),
Center(
child: ChannelInfo(
showTypingIndicator: false,
channel: StreamChannel.of(context).channel,
textStyle:
StreamChatTheme.of(context).channelPreviewTheme.subtitle,
),
),
SizedBox(
height: 17.0,
),
if (channel.isDistinct && channel.memberCount == 2)
Column(
children: [ children: [
UserAvatar( SizedBox(
user: members height: 24.0,
.firstWhere((e) => e.user.id != userAsMember.user.id) ),
.user, Center(
constraints: BoxConstraints( child: Padding(
maxHeight: 64.0, padding: const EdgeInsets.symmetric(horizontal: 16.0),
maxWidth: 64.0, child: ChannelName(
textStyle:
StreamChatTheme.of(context).textTheme.headlineBold,
),
), ),
borderRadius: BorderRadius.circular(32.0),
onlineIndicatorConstraints:
BoxConstraints.tight(Size(12.0, 12.0)),
), ),
SizedBox( SizedBox(
height: 6.0, height: 5.0,
), ),
Text( Center(
members child: ChannelInfo(
.firstWhere((e) => e.user.id != userAsMember.user.id) showTypingIndicator: false,
.user channel: StreamChannel.of(context).channel,
.name, textStyle: StreamChatTheme.of(context)
style: StreamChatTheme.of(context).textTheme.footnoteBold, .channelPreviewTheme
maxLines: 1, .subtitle,
overflow: TextOverflow.ellipsis, ),
),
SizedBox(
height: 17.0,
),
if (channel.isDistinct && channel.memberCount == 2)
Column(
children: [
UserAvatar(
user: members
.firstWhere(
(e) => e.user.id != userAsMember.user.id)
.user,
constraints: BoxConstraints(
maxHeight: 64.0,
maxWidth: 64.0,
),
borderRadius: BorderRadius.circular(32.0),
onlineIndicatorConstraints:
BoxConstraints.tight(Size(12.0, 12.0)),
),
SizedBox(
height: 6.0,
),
Text(
members
.firstWhere(
(e) => e.user.id != userAsMember.user.id)
.user
.name,
style:
StreamChatTheme.of(context).textTheme.footnoteBold,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
if (!(channel.isDistinct && channel.memberCount == 2))
Container(
height: 94.0,
alignment: Alignment.center,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: members.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: [
UserAvatar(
user: members[index].user,
constraints: BoxConstraints(
maxHeight: 64.0,
maxWidth: 64.0,
),
borderRadius: BorderRadius.circular(32.0),
onlineIndicatorConstraints:
BoxConstraints.tight(Size(12.0, 12.0)),
),
SizedBox(
height: 6.0,
),
Text(
members[index].user.name,
style: StreamChatTheme.of(context)
.textTheme
.footnoteBold,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
);
},
),
),
SizedBox(
height: 24.0,
),
OptionListTile(
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: StreamSvgIcon.user(
color: StreamChatTheme.of(context).colorTheme.grey,
),
),
title: 'View Info',
onTap: widget.onViewInfoTap,
),
if (!channel.isDistinct)
OptionListTile(
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: StreamSvgIcon.userRemove(
color: StreamChatTheme.of(context).colorTheme.grey,
),
),
title: 'Leave Group',
onTap: () async {
setState(() {
_showActions = false;
});
await _showLeaveDialog();
setState(() {
_showActions = true;
});
},
),
if (isOwner)
OptionListTile(
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: StreamSvgIcon.delete(
color: StreamChatTheme.of(context).colorTheme.accentRed,
),
),
title: 'Delete Conversation',
titleColor:
StreamChatTheme.of(context).colorTheme.accentRed,
onTap: () async {
setState(() {
_showActions = false;
});
await _showDeleteDialog();
setState(() {
_showActions = true;
});
},
),
OptionListTile(
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: StreamSvgIcon.close_small(
color: StreamChatTheme.of(context).colorTheme.grey,
),
),
title: 'Cancel',
onTap: () {
Navigator.pop(context);
},
), ),
], ],
), ),
if (!(channel.isDistinct && channel.memberCount == 2))
Container(
height: 94.0,
alignment: Alignment.center,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: members.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: [
UserAvatar(
user: members[index].user,
constraints: BoxConstraints(
maxHeight: 64.0,
maxWidth: 64.0,
),
borderRadius: BorderRadius.circular(32.0),
onlineIndicatorConstraints:
BoxConstraints.tight(Size(12.0, 12.0)),
),
SizedBox(
height: 6.0,
),
Text(
members[index].user.name,
style: StreamChatTheme.of(context)
.textTheme
.footnoteBold,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
);
},
),
),
SizedBox(
height: 24.0,
),
OptionListTile(
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: StreamSvgIcon.user(
color: StreamChatTheme.of(context).colorTheme.grey,
),
),
title: 'View Info',
onTap: widget.onViewInfoTap,
),
if (!channel.isDistinct)
OptionListTile(
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: StreamSvgIcon.userRemove(
color: StreamChatTheme.of(context).colorTheme.grey,
),
),
title: 'Leave Group',
onTap: () async {
_showLeaveDialog();
},
),
if (isOwner)
OptionListTile(
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: StreamSvgIcon.delete(
color: StreamChatTheme.of(context).colorTheme.accentRed,
),
),
title: 'Delete Conversation',
titleColor: StreamChatTheme.of(context).colorTheme.accentRed,
onTap: () async {
_showDeleteDialog();
},
),
OptionListTile(
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: StreamSvgIcon.close_small(
color: StreamChatTheme.of(context).colorTheme.grey,
),
),
title: 'Cancel',
onTap: () {
Navigator.pop(context);
},
),
],
),
); );
} }
@@ -61,6 +61,8 @@ class MessageActionsModal extends StatefulWidget {
} }
class _MessageActionsModalState extends State<MessageActionsModal> { class _MessageActionsModalState extends State<MessageActionsModal> {
bool _showActions = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return _showMessageOptionsModal(); return _showMessageOptionsModal();
@@ -87,160 +89,163 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
? 1 ? 1
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
return TweenAnimationBuilder<double>( final hasFileAttachment =
tween: Tween(begin: 0.0, end: 1.0), widget.message.attachments?.any((it) => it.type == 'file') == true;
duration: Duration(milliseconds: 300),
curve: Curves.easeInOutBack, return GestureDetector(
builder: (context, val, snapshot) { behavior: HitTestBehavior.translucent,
final hasFileAttachment = onTap: () => Navigator.maybePop(context),
widget.message.attachments?.any((it) => it.type == 'file') == true; child: Stack(
return GestureDetector( children: [
behavior: HitTestBehavior.translucent, Positioned.fill(
onTap: () => Navigator.maybePop(context), child: BackdropFilter(
child: Stack( filter: ImageFilter.blur(
children: [ sigmaX: 10,
Positioned.fill( sigmaY: 10,
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Container(
color: StreamChatTheme.of(context).colorTheme.overlay,
),
),
), ),
Transform.scale( child: Container(
scale: val, color: StreamChatTheme.of(context).colorTheme.overlay,
child: Center( ),
child: SingleChildScrollView( ),
child: Padding( ),
padding: const EdgeInsets.all(8.0), if (_showActions)
child: Column( TweenAnimationBuilder<double>(
crossAxisAlignment: widget.reverse tween: Tween(begin: 0.0, end: 1.0),
? CrossAxisAlignment.end duration: Duration(milliseconds: 300),
: CrossAxisAlignment.start, curve: Curves.easeInOutBack,
children: <Widget>[ builder: (context, val, snapshot) {
if (widget.showReactions && return Transform.scale(
(widget.message.status == scale: val,
MessageSendingStatus.SENT || child: Center(
widget.message.status == null)) child: SingleChildScrollView(
Align( child: Padding(
alignment: Alignment( padding: const EdgeInsets.all(8.0),
user.id == widget.message.user.id child: Column(
? (divFactor > 1.0 crossAxisAlignment: widget.reverse
? 0.0 ? CrossAxisAlignment.end
: (1.0 - divFactor)) : CrossAxisAlignment.start,
: (divFactor > 1.0 children: <Widget>[
? 0.0 if (widget.showReactions &&
: -(1.0 - divFactor)), (widget.message.status ==
0.0), MessageSendingStatus.SENT ||
child: ReactionPicker( widget.message.status == null))
message: widget.message, Align(
messageTheme: widget.messageTheme, alignment: Alignment(
), user.id == widget.message.user.id
), ? (divFactor > 1.0
SizedBox(height: 8), ? 0.0
IgnorePointer( : (1.0 - divFactor))
child: MessageWidget( : (divFactor > 1.0
key: Key('MessageWidget'), ? 0.0
reverse: widget.reverse, : -(1.0 - divFactor)),
message: widget.message.copyWith( 0.0),
text: widget.message.text.length > 200 child: ReactionPicker(
? '${widget.message.text.substring(0, 200)}...' message: widget.message,
: widget.message.text, messageTheme: widget.messageTheme,
),
messageTheme: widget.messageTheme,
showReactions: false,
showUsername: false,
showThreadReplyIndicator: false,
showReplyMessage: false,
showUserAvatar: widget.showUserAvatar,
attachmentPadding: EdgeInsets.all(
hasFileAttachment ? 4 : 2,
),
showTimestamp: false,
translateUserAvatar: false,
padding: const EdgeInsets.all(0),
textPadding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal:
widget.message.text.isOnlyEmoji ? 0 : 16.0,
),
showReactionPickerIndicator:
widget.showReactions &&
(widget.message.status ==
MessageSendingStatus.SENT ||
widget.message.status == null),
showInChannelIndicator: false,
showSendingIndicator: false,
shape: widget.messageShape,
attachmentShape: widget.attachmentShape,
),
),
SizedBox(height: 8),
Padding(
padding: EdgeInsets.only(
left: widget.reverse ? 0 : 40,
),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.75,
child: Material(
color: StreamChatTheme.of(context)
.colorTheme
.whiteSnow,
clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
), ),
child: Column( ),
crossAxisAlignment: SizedBox(height: 8),
CrossAxisAlignment.stretch, IgnorePointer(
children: [ child: MessageWidget(
if (widget.showReplyMessage && key: Key('MessageWidget'),
reverse: widget.reverse,
message: widget.message.copyWith(
text: widget.message.text.length > 200
? '${widget.message.text.substring(0, 200)}...'
: widget.message.text,
),
messageTheme: widget.messageTheme,
showReactions: false,
showUsername: false,
showThreadReplyIndicator: false,
showReplyMessage: false,
showUserAvatar: widget.showUserAvatar,
attachmentPadding: EdgeInsets.all(
hasFileAttachment ? 4 : 2,
),
showTimestamp: false,
translateUserAvatar: false,
padding: const EdgeInsets.all(0),
textPadding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: widget.message.text.isOnlyEmoji
? 0
: 16.0,
),
showReactionPickerIndicator:
widget.showReactions &&
(widget.message.status == (widget.message.status ==
MessageSendingStatus.SENT || MessageSendingStatus.SENT ||
widget.message.status == null) && widget.message.status == null),
widget.message.parentId == null) showInChannelIndicator: false,
_buildReplyButton(context), showSendingIndicator: false,
if (widget.showThreadReplyMessage && shape: widget.messageShape,
(widget.message.status == attachmentShape: widget.attachmentShape,
MessageSendingStatus.SENT || ),
widget.message.status == null) && ),
widget.message.parentId == null) SizedBox(height: 8),
_buildThreadReplyButton(context), Padding(
if (widget.showResendMessage) padding: EdgeInsets.only(
_buildResendMessage(context), left: widget.reverse ? 0 : 40,
if (widget.showEditMessage) ),
_buildEditMessage(context), child: SizedBox(
if (widget.showCopyMessage) width: MediaQuery.of(context).size.width * 0.75,
_buildCopyButton(context), child: Material(
if (widget.showFlagButton) color: StreamChatTheme.of(context)
_buildFlagButton(context), .colorTheme
if (widget.showDeleteMessage) .whiteSnow,
_buildDeleteButton(context), clipBehavior: Clip.hardEdge,
].insertBetween( shape: RoundedRectangleBorder(
Container( borderRadius: BorderRadius.circular(16),
height: 1, ),
color: StreamChatTheme.of(context) child: Column(
.colorTheme crossAxisAlignment:
.greyWhisper, CrossAxisAlignment.stretch,
children: [
if (widget.showReplyMessage &&
(widget.message.status ==
MessageSendingStatus.SENT ||
widget.message.status == null) &&
widget.message.parentId == null)
_buildReplyButton(context),
if (widget.showThreadReplyMessage &&
(widget.message.status ==
MessageSendingStatus.SENT ||
widget.message.status == null) &&
widget.message.parentId == null)
_buildThreadReplyButton(context),
if (widget.showResendMessage)
_buildResendMessage(context),
if (widget.showEditMessage)
_buildEditMessage(context),
if (widget.showCopyMessage)
_buildCopyButton(context),
if (widget.showFlagButton)
_buildFlagButton(context),
if (widget.showDeleteMessage)
_buildDeleteButton(context),
].insertBetween(
Container(
height: 1,
color: StreamChatTheme.of(context)
.colorTheme
.greyWhisper,
),
), ),
), ),
), ),
), ),
), ),
), ],
], ),
), ),
), ),
), ),
), );
), },
], ),
), ],
); ),
},
); );
} }
@@ -273,6 +278,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
} }
void _showDeleteDialog() async { void _showDeleteDialog() async {
setState(() {
_showActions = false;
});
var answer = await showConfirmationDialog(context, var answer = await showConfirmationDialog(context,
title: 'Delete message', title: 'Delete message',
icon: StreamSvgIcon.flag( icon: StreamSvgIcon.flag(
@@ -293,6 +301,10 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
} catch (err) { } catch (err) {
_showErrorAlert(); _showErrorAlert();
} }
} else {
setState(() {
_showActions = true;
});
} }
} }
@@ -1026,7 +1026,11 @@ class MessageInputState extends State<MessageInput> {
setState(() { setState(() {
_attachments.add(attachment); _attachments.add(attachment);
}); });
final mediaFile = await medium.originFile;
final mediaFile = await medium.originFile.timeout(
Duration(seconds: 5),
onTimeout: () => medium.originFile,
);
var file = PlatformFile( var file = PlatformFile(
path: mediaFile.path, path: mediaFile.path,
@@ -813,9 +813,7 @@ class _MessageListViewState extends State<MessageListView> {
final readList = channel.state?.read?.where((read) { final readList = channel.state?.read?.where((read) {
if (read.user.id == userId) return false; if (read.user.id == userId) return false;
return (read.lastRead.isAfter(message.createdAt) || return (read.lastRead.isAfter(message.createdAt) ||
read.lastRead.isAtSameMomentAs(message.createdAt)) && read.lastRead.isAtSameMomentAs(message.createdAt));
(index == 0 ||
read.lastRead.isBefore(messages[index - 1].createdAt));
})?.toList() ?? })?.toList() ??
[]; [];
@@ -381,12 +381,14 @@ class _MessageWidgetState extends State<MessageWidget> {
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
elevation: 0.0, elevation: 0.0,
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
horizontal: horizontal: (isFailedState
widget.showUserAvatar == ? 15.0
: 0.0) +
(widget.showUserAvatar ==
DisplayWidget DisplayWidget
.gone .gone
? 0 ? 0
: 4.0, : 4.0),
), ),
shape: widget.shape ?? shape: widget.shape ??
RoundedRectangleBorder( RoundedRectangleBorder(
@@ -453,16 +455,10 @@ class _MessageWidgetState extends State<MessageWidget> {
), ),
if (isFailedState) if (isFailedState)
Positioned( Positioned(
left: widget.reverse ? -3 : null, left: widget.reverse ? 0 : null,
right: widget.reverse ? null : -9, right: widget.reverse ? null : 0,
bottom: showBottomRow ? 20 : 0, bottom: showBottomRow ? 18 : -2,
child: Container( child: StreamSvgIcon.error(size: 20),
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: StreamSvgIcon.error(size: 20),
),
), ),
], ],
), ),
@@ -80,7 +80,6 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
primaryIconTheme: streamTheme.primaryIconTheme, primaryIconTheme: streamTheme.primaryIconTheme,
accentColor: streamTheme.colorTheme.accentBlue, accentColor: streamTheme.colorTheme.accentBlue,
scaffoldBackgroundColor: streamTheme.colorTheme.white, scaffoldBackgroundColor: streamTheme.colorTheme.white,
buttonTheme: streamTheme.buttonTheme,
), ),
child: widget.child, child: widget.child,
); );