chore: 1.5.1 (#387)

* lint(persistence): Apply team linter

Signed-off-by: Sahil Kumar <[email protected]>

* style: flutter format

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): Add tests for channel dao

Signed-off-by: Sahil Kumar <[email protected]>

* refactor(persistence): remove dummy comments

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): Add test for channel query dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for connection event dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add test for member dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for message dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add test for pinned message dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add test for reaction dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add test for read dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): minor improvement in update function tests

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for user dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add test for list converter

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add test for map converter

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for message sending status converter

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for channel mapper

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add test for event mapper

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for member mapper

Signed-off-by: Sahil Kumar <[email protected]>

* remove useless dependencies

* test(persistence): add tests for message mapper

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for pinned message mapper

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for reaction mapper

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for read mapper

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for user mapper

Signed-off-by: Sahil Kumar <[email protected]>

* refactor(persistence): remove redundant UsersTable getter from ConnectionEventDao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests for stream chat persistence client

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add tests moor chat database

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add moor schemas for future migration tests

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add clear queryCache test in channel query dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add getThreadMessagesByParentId along with pagination test in message, pinned message dao.

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add getMessagesByCid along with pagination test in message, pinned message dao.

Signed-off-by: Sahil Kumar <[email protected]>

* update ci

* apply locale to jiffy

* fix test

* test(persistence): add getMessagesByCid along with quotedMessage test in message, pinned message dao.

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add extra checks in getMessagesByCid along with pagination test in message, pinned message dao.

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add return channel with pagination applies test in channel query dao

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): improve message mapper, pinned message mapper test

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add client constructor test in stream chat persistence client

Signed-off-by: Sahil Kumar <[email protected]>

* test(persistence): add coverage:ignore-file for entities and db/shared directory

Signed-off-by: Sahil Kumar <[email protected]>

* skip pub publish --dry-run for develop branch

Signed-off-by: Sahil Kumar <[email protected]>

* add remove from coverage script

Signed-off-by: Sahil Kumar <[email protected]>

* fix

Signed-off-by: Sahil Kumar <[email protected]>

* fix

Signed-off-by: Sahil Kumar <[email protected]>

* fix

Signed-off-by: Sahil Kumar <[email protected]>

* fix

Signed-off-by: Sahil Kumar <[email protected]>

* fix locale

* fix message input _parseExistingMessage

* fix(UI-Kit): Show selected attachment file as file in message input widget

Signed-off-by: Sahil Kumar <[email protected]>

* fix: ws disconnection (#345)

* update ws removing custom implementation; fixed disconnection while connecting

* add test

* feat: Apply team lints to core package (#334)

* Add analyzer file to core package

* Apply team lint rules to core package

* clean up analyzer warnings in stream chat flutter

* remove unused line

* add ignore

* sync analysis options

* [Core -> MessageWidget] Fix variable dynamic types

Signed-off-by: Sahil Kumar <[email protected]>

Co-authored-by: Salvatore Giordano <[email protected]>
Co-authored-by: Sahil Kumar <[email protected]>

* test: add tests for stream chat flutter core (#354)

* test(core): add tests for channels bloc

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): refactor some tests due to changes in channels bloc

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): add tests for channel list core

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): add tests for users bloc, minor improvements

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): add tests for user list core, minor improvements

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): add tests for message search bloc, refactor

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): add tests for message search list core, refactor

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): add tests for lazy load scroll view

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): add tests for stream chat core

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): add tests for message list core

Signed-off-by: Sahil Kumar <[email protected]>

* test(core): add tests for stream channel

Signed-off-by: Sahil Kumar <[email protected]>

* Fix merge conflicts

Signed-off-by: Sahil Kumar <[email protected]>

* flutter format

Signed-off-by: Sahil Kumar <[email protected]>

* fixes

Signed-off-by: Sahil Kumar <[email protected]>

* update workflow

Signed-off-by: Sahil Kumar <[email protected]>

* chore(core): fix analyzer issues

Signed-off-by: Sahil Kumar <[email protected]>

* chore(ui-kit): fix analyzer issues

Signed-off-by: Sahil Kumar <[email protected]>

* refactor(ui-kit): update giphy interaction (#361)

* refactor(ui-kit): update giphy interaction

Signed-off-by: Sahil Kumar <[email protected]>

* fix overflow

Co-authored-by: Salvatore Giordano <[email protected]>

* fix: Fixed sendingbutton.outside case (#355)

* fix: Fixed sendingbutton.outside case

* fix: Fixed all actionbutton cases

* fix review

Co-authored-by: Salvatore Giordano <[email protected]>

* fix(ui-kit): fix accessibility text size scaling in message widget

Signed-off-by: Sahil Kumar <[email protected]>

* fix(ui-kit): fix message widget long username overflow

Signed-off-by: Sahil Kumar <[email protected]>

* fix(ui-kit): fix message input dm checkbox accessibility scaling issue

Signed-off-by: Sahil Kumar <[email protected]>

* feat: exposed textbuilder callback (#367)

* exposed textbuilder callback

* exposed textbuilder callback

* fixes

Signed-off-by: Sahil Kumar <[email protected]>

* check if user.mutes is null

* check if user.mutes is null

* fixes #370: remove all controls on full screen media if message is of type ephemeral (#373)

* fix: fix channel list pagination spinner (#375)

Signed-off-by: Sahil Kumar <[email protected]>

* fix: attachments upload when size exceeds (#377)

* fix: Fixed file upload error

* fix: Fixed file upload error

* fix coverage script

Signed-off-by: Sahil Kumar <[email protected]>

* fix: message input (#382)

* feat: Added mentions suffix builder

* feat: Added builders for mentions and theme element for message input expanded button

* refactor: refactored PR to suit other style

* fix: fixes trailing commas and changes names

* doc: added documentation to new elements

* doc: added documentation to new elements

* bump version

* add meta dep to core

* sort deps

Co-authored-by: Sahil Kumar <[email protected]>
Co-authored-by: Neevash Ramdial (Nash) <[email protected]>
Co-authored-by: Deven Joshi <[email protected]>
This commit is contained in:
Salvatore Giordano
2021-04-07 12:24:29 +02:00
committed by GitHub
co-authored by Sahil Kumar Neevash Ramdial Deven Joshi
parent aeb6da8d38
commit 87ca818a9a
119 changed files with 11223 additions and 1240 deletions
@@ -1,3 +1,9 @@
## 1.5.2
- Fix accessibility text size overflows
- Updated Giphy attachment ui
- Minor fixes and improvements
## 1.5.1
- Fixed unread count not updating while the chat is open
@@ -59,138 +59,57 @@ class GiphyAttachment extends AttachmentWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Stack(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () => onAttachmentTap ?? _onImageTap(context),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
child: CachedNetworkImage(
height: size?.height,
width: size?.width,
placeholder: (_, __) {
return Container(
width: size?.width,
height: size?.height,
child: Center(
child: CircularProgressIndicator(),
),
);
},
imageUrl: imageUrl,
errorWidget: (context, url, error) {
return AttachmentError(size: size);
},
fit: BoxFit.cover,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
StreamSvgIcon.giphyIcon(),
SizedBox(width: 8),
Text(
'Giphy',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Positioned(
bottom: 16,
left: 16,
child: Material(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 4.0,
),
child: Row(
children: [
StreamSvgIcon.lightning(
color:
StreamChatTheme.of(context).colorTheme.white,
size: 16,
),
Text(
'GIPHY',
style: TextStyle(
color: StreamChatTheme.of(context)
.colorTheme
.white,
fontWeight: FontWeight.bold,
fontSize: 11,
),
),
],
SizedBox(width: 8),
if (attachment.title != null)
Flexible(
child: Text(
attachment.title,
style: TextStyle(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.5),
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
),
),
],
],
),
),
if (attachment.title != null)
Container(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Card(
color: Colors.white,
elevation: 2,
shape: CircleBorder(),
child: IconButton(
padding: const EdgeInsets.all(0),
constraints: BoxConstraints.tight(Size(32, 32)),
icon: StreamSvgIcon.left(
size: 24.0,
),
splashRadius: 16,
onPressed: () {
streamChannel.channel.sendAction(message, {
'image_action': 'shuffle',
});
},
),
Padding(
padding: const EdgeInsets.all(2.0),
child: GestureDetector(
onTap: () => onAttachmentTap ?? _onImageTap(context),
child: CachedNetworkImage(
height: size?.height,
width: size?.width,
placeholder: (_, __) {
return Container(
width: size?.width,
height: size?.height,
child: Center(
child: CircularProgressIndicator(),
),
Expanded(
child: Center(
child: Text(
'"${attachment.title}"',
style: TextStyle(
fontStyle: FontStyle.italic,
),
),
),
),
Card(
color: Colors.white,
elevation: 2,
shape: CircleBorder(),
child: IconButton(
padding: const EdgeInsets.all(0),
constraints: BoxConstraints.tight(Size(32, 32)),
icon: StreamSvgIcon.right(
size: 24.0,
),
splashRadius: 16,
onPressed: () {
streamChannel.channel.sendAction(message, {
'image_action': 'shuffle',
});
},
),
),
],
),
);
},
imageUrl: imageUrl,
errorWidget: (context, url, error) {
return AttachmentError(size: size);
},
fit: BoxFit.cover,
),
),
SizedBox(
height: 4.0,
),
Container(
color: StreamChatTheme.of(context)
@@ -236,6 +155,38 @@ class GiphyAttachment extends AttachmentWidget {
.withOpacity(0.2),
height: 50.0,
),
Expanded(
child: Container(
height: 50,
child: TextButton(
onPressed: () {
streamChannel.channel.sendAction(message, {
'image_action': 'shuffle',
});
},
child: Text(
'Shuffle',
style: StreamChatTheme.of(context)
.textTheme
.bodyBold
.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.5),
),
),
),
),
),
Container(
width: 0.5,
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.2),
height: 50.0,
),
Expanded(
child: Container(
height: 50,
@@ -261,9 +212,7 @@ class GiphyAttachment extends AttachmentWidget {
],
),
),
SizedBox(
height: 4.0,
),
SizedBox(height: 4.0),
Align(
alignment: Alignment.centerRight,
child: Padding(
@@ -143,7 +143,7 @@ class _ChannelFileDisplayScreenState extends State<ChannelFileDisplayScreen> {
}
return LazyLoadScrollView(
onEndOfPage: () => messageSearchBloc.loadMore(
onEndOfPage: () => messageSearchBloc.search(
filter: {
'cid': {
r'$in': [StreamChannel.of(context).channel.cid]
@@ -628,13 +628,14 @@ class _ChannelListViewState extends State<ChannelListView> {
),
);
}
return Container(
height: 100,
padding: EdgeInsets.all(32),
child: Center(
child: snapshot.data ? CircularProgressIndicator() : Container(),
),
);
return snapshot.data
? Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: const CircularProgressIndicator(),
),
)
: Offstage();
});
}
@@ -166,7 +166,7 @@ class _ChannelMediaDisplayScreenState extends State<ChannelMediaDisplayScreen> {
}
return LazyLoadScrollView(
onEndOfPage: () => messageSearchBloc.loadMore(
onEndOfPage: () => messageSearchBloc.search(
filter: {
'cid': {
r'$in': [StreamChannel.of(context).channel.cid]
@@ -170,14 +170,14 @@ class ChannelPreview extends StatelessWidget {
if (lastMessageAt.millisecondsSinceEpoch >=
startOfDay.millisecondsSinceEpoch) {
stringDate = Jiffy(lastMessageAt.toLocal()).format('HH:mm');
stringDate = Jiffy(lastMessageAt.toLocal()).jm;
} else if (lastMessageAt.millisecondsSinceEpoch >=
startOfDay.subtract(Duration(days: 1)).millisecondsSinceEpoch) {
stringDate = 'Yesterday';
} else if (startOfDay.difference(lastMessageAt).inDays < 7) {
stringDate = Jiffy(lastMessageAt.toLocal()).EEEE;
} else {
stringDate = Jiffy(lastMessageAt.toLocal()).format('dd/MM/yyyy');
stringDate = Jiffy(lastMessageAt.toLocal()).yMd;
}
return Text(
@@ -28,14 +28,14 @@ class DateDivider extends StatelessWidget {
now.subtract(Duration(days: 7)),
Units.DAY,
)) {
dayInfo = createdAt.format('EEEE');
dayInfo = createdAt.EEEE;
} else if (Jiffy(createdAt).isAfter(
Jiffy(now).subtract(years: 1),
Units.DAY,
)) {
dayInfo = createdAt.format('MMMM d');
dayInfo = createdAt.MMMd;
} else {
dayInfo = createdAt.format('MMMM d');
dayInfo = createdAt.MMMd;
}
if (uppercase) dayInfo = dayInfo.toUpperCase();
@@ -97,3 +97,8 @@ extension InputDecorationX on InputDecoration {
);
}
}
extension BuildContextX on BuildContext {
double get textScaleFactor =>
MediaQuery.maybeOf(this)?.textScaleFactor ?? 1.0;
}
@@ -185,21 +185,22 @@ class _FullScreenMediaState extends State<FullScreenMedia>
widget.message, StreamChannel.of(context).channel);
},
),
ImageFooter(
currentPage: _currentPage,
totalPages: widget.mediaAttachments.length,
mediaAttachments: widget.mediaAttachments,
message: widget.message,
mediaSelectedCallBack: (val) {
setState(() {
_currentPage = val;
_pageController.animateToPage(val,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut);
Navigator.pop(context);
});
},
),
if (widget.message.type != 'ephemeral')
ImageFooter(
currentPage: _currentPage,
totalPages: widget.mediaAttachments.length,
mediaAttachments: widget.mediaAttachments,
message: widget.message,
mediaSelectedCallBack: (val) {
setState(() {
_currentPage = val;
_pageController.animateToPage(val,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut);
Navigator.pop(context);
});
},
),
],
),
),
@@ -220,7 +221,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
24) {
return 'yesterday';
} else {
return 'on ${Jiffy(dateTime).format("MMM do")}';
return 'on ${Jiffy(dateTime).MMMd}';
}
}
@@ -78,6 +78,7 @@ class _ImageFooterState extends State<ImageFooter> {
@override
Widget build(BuildContext context) {
final showShareButton = !kIsWeb;
return SizedBox.fromSize(
size: Size(
MediaQuery.of(context).size.width,
@@ -91,8 +92,10 @@ class _ImageFooterState extends State<ImageFooter> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
kIsWeb
? SizedBox()
!showShareButton
? Container(
width: 48,
)
: IconButton(
icon: StreamSvgIcon.iconShare(
size: 24.0,
@@ -63,38 +63,43 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
backgroundColor:
StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color,
actions: <Widget>[
IconButton(
icon: StreamSvgIcon.iconMenuPoint(
color: StreamChatTheme.of(context).colorTheme.black,
if (message.type != 'ephemeral')
IconButton(
icon: StreamSvgIcon.iconMenuPoint(
color: StreamChatTheme.of(context).colorTheme.black,
),
onPressed: () {
_showMessageActionModalBottomSheet(context);
},
),
onPressed: () {
_showMessageActionModalBottomSheet(context);
},
),
],
centerTitle: true,
title: InkWell(
onTap: onTitleTap,
child: Container(
height: preferredSize.height,
width: preferredSize.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
userName,
style: StreamChatTheme.of(context).textTheme.headlineBold,
title: message.type != 'ephemeral'
? InkWell(
onTap: onTitleTap,
child: Container(
height: preferredSize.height,
width: preferredSize.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
userName,
style: StreamChatTheme.of(context).textTheme.headlineBold,
),
Text(
sentAt,
style: StreamChatTheme.of(context)
.channelPreviewTheme
.subtitle,
),
],
),
),
Text(
sentAt,
style: StreamChatTheme.of(context).channelPreviewTheme.subtitle,
),
],
),
),
),
)
: SizedBox(),
);
}
@@ -0,0 +1,99 @@
import 'package:flutter/material.dart';
import '../stream_chat_flutter.dart';
/// This widget is used for showing user tiles for mentions
/// Use [title], [subtitle], [leading], [trailing] for substituting widgets in respective positions
class MentionTile extends StatelessWidget {
/// Member to display in the tile
final Member member;
/// Widget to display as title
final Widget title;
/// Widget to display below [title]
final Widget subtitle;
/// Widget at the start of the tile
final Widget leading;
/// Widget at the end of tile
final Widget trailing;
MentionTile(
this.member, {
this.title,
this.subtitle,
this.leading,
this.trailing,
});
@override
Widget build(BuildContext context) {
return Container(
height: 56.0,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 16.0,
),
leading ??
UserAvatar(
constraints: BoxConstraints.tight(
Size(
40,
40,
),
),
user: member.user,
),
SizedBox(
width: 8.0,
),
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title ??
Text(
'${member.user.name}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: StreamChatTheme.of(context).textTheme.bodyBold,
),
SizedBox(
height: 2.0,
),
subtitle ??
Text(
'@${member.userId}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: StreamChatTheme.of(context)
.textTheme
.footnoteBold
.copyWith(
color:
StreamChatTheme.of(context).colorTheme.grey,
),
),
],
),
),
),
trailing ??
Padding(
padding: const EdgeInsets.only(right: 18.0, left: 8.0),
child: StreamSvgIcon.mentions(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
),
),
],
),
);
}
}
@@ -16,7 +16,6 @@ import 'package:stream_chat_flutter/src/media_list_view.dart';
import 'package:stream_chat_flutter/src/message_list_view.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_avatar.dart';
import 'package:stream_chat_flutter/src/video_service.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:substring_highlight/substring_highlight.dart';
@@ -32,6 +31,13 @@ typedef AttachmentThumbnailBuilder = Widget Function(
Attachment,
);
/// Builder function for building a mention tile
/// Use [MentionTile] for the default implementation
typedef MentionTileBuilder = Widget Function(
BuildContext context,
Member member,
);
enum ActionsLocation {
left,
right,
@@ -125,6 +131,7 @@ class MessageInput extends StatefulWidget {
this.idleSendButton,
this.activeSendButton,
this.showCommandsButton = true,
this.mentionsTileBuilder,
}) : super(key: key);
/// Message to edit
@@ -191,6 +198,9 @@ class MessageInput extends StatefulWidget {
/// Send button widget in an active state
final Widget activeSendButton;
/// Customize the tile for the mentions overlay
final MentionTileBuilder mentionsTileBuilder;
@override
MessageInputState createState() => MessageInputState();
@@ -319,7 +329,11 @@ class MessageInputState extends State<MessageInput> {
),
if (widget.parentMessage != null && !widget.hideSendAsDm)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
padding: const EdgeInsets.only(
right: 12.0,
left: 12.0,
bottom: 12.0,
),
child: _buildDmCheckbox(),
),
_buildFilePickerSection(),
@@ -354,68 +368,68 @@ class MessageInputState extends State<MessageInput> {
}
Widget _buildDmCheckbox() {
return Container(
height: 36,
padding: const EdgeInsets.only(
left: 12,
bottom: 12,
top: 8,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 16,
width: 16,
foregroundDecoration: BoxDecoration(
border: _sendAsDm
? null
: Border.all(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(.5),
width: 2,
),
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 16,
width: 16,
foregroundDecoration: BoxDecoration(
border: _sendAsDm
? null
: Border.all(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(.5),
width: 2,
),
borderRadius: BorderRadius.circular(3),
),
child: Center(
child: Material(
borderRadius: BorderRadius.circular(3),
),
child: Center(
child: Material(
borderRadius: BorderRadius.circular(3),
color: _sendAsDm
? StreamChatTheme.of(context).colorTheme.accentBlue
: StreamChatTheme.of(context).colorTheme.white,
child: InkWell(
onTap: () {
setState(() {
_sendAsDm = !_sendAsDm;
});
},
child: AnimatedCrossFade(
duration: Duration(milliseconds: 300),
reverseDuration: Duration(milliseconds: 300),
crossFadeState: _sendAsDm
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
firstChild: StreamSvgIcon.check(
size: 16.0,
color: StreamChatTheme.of(context).colorTheme.white,
),
secondChild: SizedBox(
height: 16,
width: 16,
),
color: _sendAsDm
? StreamChatTheme.of(context).colorTheme.accentBlue
: StreamChatTheme.of(context).colorTheme.white,
child: InkWell(
onTap: () {
setState(() {
_sendAsDm = !_sendAsDm;
});
},
child: AnimatedCrossFade(
duration: Duration(milliseconds: 300),
reverseDuration: Duration(milliseconds: 300),
crossFadeState: _sendAsDm
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
firstChild: StreamSvgIcon.check(
size: 16.0,
color: StreamChatTheme.of(context).colorTheme.white,
),
secondChild: SizedBox(
height: 16,
width: 16,
),
),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text('Also send as direct message'),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Text(
'Also send as direct message',
style: StreamChatTheme.of(context).textTheme.footnote.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.5),
),
),
],
),
),
],
);
}
@@ -454,7 +468,9 @@ class MessageInputState extends State<MessageInput> {
? pi
: 0,
child: StreamSvgIcon.emptyCircleLeft(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
color: StreamChatTheme.of(context)
.messageInputTheme
.expandButtonColor,
),
),
padding: const EdgeInsets.all(0),
@@ -491,10 +507,17 @@ class MessageInputState extends State<MessageInput> {
Expanded _buildTextInput(BuildContext context) {
final theme = StreamChatTheme.of(context);
final margin = (widget.sendButtonLocation == SendButtonLocation.inside
? const EdgeInsets.only(right: 8.0)
: EdgeInsets.zero) +
(widget.actionsLocation != ActionsLocation.left
? const EdgeInsets.only(left: 8.0)
: EdgeInsets.zero);
return Expanded(
child: Center(
child: Container(
clipBehavior: Clip.antiAlias,
margin: margin,
decoration: BoxDecoration(
borderRadius: theme.messageInputTheme.borderRadius,
gradient: _focusNode.hasFocus
@@ -656,6 +679,7 @@ class MessageInputState extends State<MessageInput> {
Timer _debounce;
String _previousValue;
void _onChanged(BuildContext context, String s) {
if (s == _previousValue) {
return;
@@ -1113,6 +1137,7 @@ class MessageInputState extends State<MessageInput> {
_showErrorAlert(
'The file is too large to upload. The file size limit is 20MB.',
);
return;
}
}
@@ -1301,80 +1326,9 @@ class MessageInputState extends State<MessageInput> {
_mentionsOverlay?.remove();
_mentionsOverlay = null;
},
child: Container(
height: 56.0,
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
SizedBox(
width: 16.0,
),
UserAvatar(
constraints: BoxConstraints.tight(
Size(
40,
40,
),
),
user: m.user,
),
SizedBox(
width: 8.0,
),
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'${m.user.name}',
maxLines: 1,
overflow:
TextOverflow.ellipsis,
style: StreamChatTheme.of(
context)
.textTheme
.bodyBold,
),
SizedBox(
height: 2.0,
),
Text(
'@${m.userId}',
maxLines: 1,
overflow:
TextOverflow.ellipsis,
style: StreamChatTheme.of(
context)
.textTheme
.footnoteBold
.copyWith(
color: StreamChatTheme
.of(context)
.colorTheme
.grey),
),
],
),
),
),
Padding(
padding: const EdgeInsets.only(
right: 18.0, left: 8.0),
child: StreamSvgIcon.mentions(
color: StreamChatTheme.of(context)
.colorTheme
.accentBlue,
),
),
],
),
),
child: widget.mentionsTileBuilder != null
? widget.mentionsTileBuilder(context, m)
: MentionTile(m),
),
);
},
@@ -1962,12 +1916,6 @@ class MessageInputState extends State<MessageInput> {
final extraDataMap = <String, dynamic>{};
if (mimeType?.type == 'video' || mimeType?.type == 'image') {
attachmentType = mimeType.type;
} else {
attachmentType = 'file';
}
if (mimeType?.subtype != null) {
extraDataMap['mime_type'] = mimeType.subtype.toLowerCase();
}
@@ -1982,8 +1930,6 @@ class MessageInputState extends State<MessageInput> {
extraData: extraDataMap.isNotEmpty ? extraDataMap : null,
);
_attachments[attachment.id] = attachment;
if (file.size > _kMaxAttachmentSize) {
if (attachmentType == 'Video') {
final mediaInfo = await VideoService.compressVideo(file.path);
@@ -1992,7 +1938,6 @@ class MessageInputState extends State<MessageInput> {
_showErrorAlert(
'The file is too large to upload. The file size limit is 20MB. We tried compressing it, but it was not enough.',
);
_attachments.remove(attachment.id);
return;
}
file = AttachmentFile(
@@ -2005,9 +1950,12 @@ class MessageInputState extends State<MessageInput> {
_showErrorAlert(
'The file is too large to upload. The file size limit is 20MB.',
);
return;
}
}
_attachments[attachment.id] = attachment;
setState(() {
_attachments.update(attachment.id, (it) {
return it.copyWith(
@@ -2233,7 +2181,7 @@ class MessageInputState extends State<MessageInput> {
void _parseExistingMessage(Message message) {
textEditingController.text = message.text;
_messageIsPresent = true;
for (final attachment in message.attachments) {
for (final attachment in message?.attachments) {
_attachments[attachment.id] = attachment.copyWith(
uploadState: attachment.uploadState ?? UploadState.success(),
);
@@ -141,6 +141,7 @@ class MessageListView extends StatefulWidget {
this.onMessageTap,
this.onSystemMessageTap,
this.onAttachmentTap,
this.textBuilder,
}) : super(key: key);
/// Function used to build a custom message widget
@@ -230,9 +231,12 @@ class MessageListView extends StatefulWidget {
/// Called when system message is tapped
final OnMessageTap onSystemMessageTap;
// Customize onTap on attachment
/// Customize onTap on attachment
final void Function(Message message, Attachment attachment) onAttachmentTap;
/// Customize the MessageWidget textBuilder
final void Function(BuildContext context, Message message) textBuilder;
@override
_MessageListViewState createState() => _MessageListViewState();
}
@@ -839,6 +843,7 @@ class _MessageListViewState extends State<MessageListView> {
}
FocusScope.of(context).unfocus();
},
textBuilder: widget.textBuilder,
);
}
@@ -1015,6 +1020,7 @@ class _MessageListViewState extends State<MessageListView> {
FocusScope.of(context).unfocus();
},
onAttachmentTap: widget.onAttachmentTap,
textBuilder: widget.textBuilder,
);
if (!message.isDeleted &&
@@ -84,9 +84,9 @@ class MessageSearchItem extends StatelessWidget {
if (now.year != createdAt.year ||
now.month != createdAt.month ||
now.day != createdAt.day) {
stringDate = Jiffy(createdAt.toLocal()).format('dd/MM/yyyy');
stringDate = Jiffy(createdAt.toLocal()).yMd;
} else {
stringDate = Jiffy(createdAt.toLocal()).format('HH:mm');
stringDate = Jiffy(createdAt.toLocal()).jm;
}
return Text(
@@ -262,17 +262,13 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
);
if (widget.pullToRefresh) {
child = RefreshIndicator(
onRefresh: () async {
_messageSearchListController.loadData();
},
onRefresh: () => _messageSearchListController.loadData(),
child: child,
);
}
child = LazyLoadScrollView(
onEndOfPage: () async {
return _messageSearchListController.paginateData();
},
onEndOfPage: () => _messageSearchListController.paginateData(),
child: child,
);
@@ -585,7 +585,8 @@ class _MessageWidgetState extends State<MessageWidget>
),
],
),
if (showBottomRow) SizedBox(height: 20.0),
if (showBottomRow)
SizedBox(height: context.textScaleFactor * 18.0),
],
),
if (showBottomRow)
@@ -682,6 +683,8 @@ class _MessageWidgetState extends State<MessageWidget>
}
};
const usernameKey = Key('username');
children.addAll([
if (showInChannel || showThreadReplyIndicator) ...[
if (showThreadParticipants)
@@ -697,7 +700,10 @@ class _MessageWidgetState extends State<MessageWidget>
if (showUsername)
Text(
widget.message.user.name,
maxLines: 1,
key: usernameKey,
style: widget.messageTheme.messageAuthor,
overflow: TextOverflow.ellipsis,
),
if (showTimeStamp)
Text(
@@ -710,18 +716,17 @@ class _MessageWidgetState extends State<MessageWidget>
final showThreadTail = !(hasUrlAttachments || isGiphy || isOnlyEmoji) &&
(showThreadReplyIndicator || showInChannel);
return Flex(
direction: Axis.horizontal,
clipBehavior: Clip.none,
return Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (showThreadTail)
Container(
margin: EdgeInsets.only(
bottom: widget.messageTheme.replies.fontSize / 2,
bottom: context.textScaleFactor *
(widget.messageTheme.replies.fontSize / 2),
),
child: CustomPaint(
size: const Size(16, 32),
size: Size(16, 32) * context.textScaleFactor,
painter: _ThreadReplyPainter(
context: context,
color: widget.messageTheme.messageBorderColor,
@@ -729,16 +734,20 @@ class _MessageWidgetState extends State<MessageWidget>
),
),
...children.map(
(child) => Transform(
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
alignment: Alignment.center,
child: Container(
height: 16,
child: Center(
(child) {
Widget mappedChild = Transform(
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
alignment: Alignment.center,
child: Container(
height: context.textScaleFactor * 14,
child: child,
),
),
),
);
if (child.key == usernameKey) {
mappedChild = Flexible(child: mappedChild);
}
return mappedChild;
},
),
].insertBetween(const SizedBox(width: 8.0)),
);
@@ -3,9 +3,11 @@ import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:jiffy/jiffy.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'dart:ui' as ui;
/// Widget used to provide information about the chat to the widget tree
///
@@ -121,4 +123,11 @@ class StreamChatState extends State<StreamChat> {
void initState() {
super.initState();
}
@override
void didChangeDependencies() {
final locale = ui.window.locale;
Jiffy.locale(locale.languageCode);
super.didChangeDependencies();
}
}
@@ -272,6 +272,7 @@ class StreamChatThemeData {
sendAnimationDuration: Duration(milliseconds: 300),
actionButtonColor: colorTheme.accentBlue,
actionButtonIdleColor: colorTheme.grey,
expandButtonColor: colorTheme.accentBlue,
sendButtonColor: colorTheme.accentBlue,
sendButtonIdleColor: colorTheme.greyGainsboro,
inputBackground: colorTheme.white,
@@ -935,6 +936,9 @@ class MessageInputTheme {
/// Background color of [MessageInput] action buttons
final Color actionButtonIdleColor;
/// Background color of [MessageInput] expand button
final Color expandButtonColor;
/// Background color of [MessageInput]
final Color inputBackground;
@@ -966,6 +970,7 @@ class MessageInputTheme {
this.activeBorderGradient,
this.idleBorderGradient,
this.borderRadius,
this.expandButtonColor,
});
/// Returns a new [MessageInputTheme] replacing some of its properties
@@ -976,6 +981,7 @@ class MessageInputTheme {
Color sendButtonColor,
Color actionButtonIdleColor,
Color sendButtonIdleColor,
Color expandButtonColor,
TextStyle inputTextStyle,
InputDecoration inputDecoration,
Gradient activeBorderGradient,
@@ -990,6 +996,7 @@ class MessageInputTheme {
sendButtonColor: sendButtonColor ?? this.sendButtonColor,
actionButtonIdleColor:
actionButtonIdleColor ?? this.actionButtonIdleColor,
expandButtonColor: expandButtonColor ?? this.expandButtonColor,
inputTextStyle: inputTextStyle ?? this.inputTextStyle,
sendButtonIdleColor: sendButtonIdleColor ?? this.sendButtonIdleColor,
inputDecoration: inputDecoration ?? this.inputDecoration,
@@ -1014,6 +1021,7 @@ class MessageInputTheme {
activeBorderGradient: other.activeBorderGradient,
idleBorderGradient: other.idleBorderGradient,
borderRadius: other.borderRadius,
expandButtonColor: other.expandButtonColor,
);
}
}
@@ -193,9 +193,7 @@ class _UserListViewState extends State<UserListView>
return child;
} else {
return RefreshIndicator(
onRefresh: () async {
_userListController.loadData();
},
onRefresh: () => _userListController.loadData(),
child: child,
);
}
@@ -243,9 +241,7 @@ class _UserListViewState extends State<UserListView>
child: Text(message),
),
TextButton(
onPressed: () {
_userListController.loadData();
},
onPressed: () => _userListController.loadData(),
child: Text('Retry'),
),
],
@@ -300,9 +296,7 @@ class _UserListViewState extends State<UserListView>
);
return LazyLoadScrollView(
onEndOfPage: () async {
return _userListController.paginateData();
},
onEndOfPage: () => _userListController.paginateData(),
child: child,
);
}
@@ -39,4 +39,5 @@ export 'src/channel_media_display_screen.dart';
export 'src/info_tile.dart';
export 'src/stream_chat.dart';
export 'src/connection_status_builder.dart';
export 'src/mention_tile.dart';
export 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
+2 -5
View File
@@ -1,7 +1,7 @@
name: stream_chat_flutter
homepage: https://github.com/GetStream/stream-chat-flutter
description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter.
version: 1.5.1
version: 1.5.2
repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -11,7 +11,7 @@ environment:
dependencies:
flutter:
sdk: flutter
stream_chat_flutter_core: ^1.5.0
stream_chat_flutter_core: ^1.5.1
photo_view: ^0.11.0
rxdart: ^0.25.0
scrollable_positioned_list: ^0.1.8
@@ -30,16 +30,13 @@ dependencies:
flutter_keyboard_visibility: ^4.0.2
video_compress: ^2.1.1
visibility_detector: ^0.1.5
http_parser: ^3.1.4
meta: ^1.2.4
lottie: ^0.7.0+1
substring_highlight: ^0.1.2
flutter_slidable: ^0.5.7
clipboard: ^0.1.2+8
image_gallery_saver: ^1.6.7
share_plus: ^1.2.0
photo_manager: ^1.0.0
transparent_image: ^1.0.0
ezanimation: ^0.4.1
synchronized: ^2.1.0
characters: ^1.0.0
@@ -69,7 +69,7 @@ void main() {
),
));
expect(find.text('22/06/2020'), findsOneWidget);
expect(find.text('6/22/2020'), findsOneWidget);
expect(find.text('test name'), findsOneWidget);
expect(find.text('1'), findsOneWidget);
expect(find.text('hello'), findsOneWidget);