Merge branch 'feature/new-ui' into feature/mono-repo

This commit is contained in:
Salvatore Giordano
2021-01-15 14:36:31 +01:00
11 changed files with 352 additions and 338 deletions
@@ -729,17 +729,11 @@ class _ChannelListViewState extends State<ChannelListView>
}
Widget _separatorBuilder(context, i) {
var effect = StreamChatTheme.of(context).colorTheme.borderTop;
var effect = StreamChatTheme.of(context).colorTheme.borderBottom;
return BackdropFilter(
filter: ui.ImageFilter.blur(
sigmaX: effect.sigmaX,
sigmaY: effect.sigmaY,
),
child: Container(
height: 1,
color: effect.color.withOpacity(0.08),
),
return Container(
height: 1,
color: effect.color.withOpacity(effect.alpha ?? 1.0),
);
}
@@ -15,13 +15,7 @@ extension StringExtension on String {
final characters = this.trim().characters;
if (characters.isEmpty) return false;
if (characters.length > 3) return false;
return characters.every((c) {
return _emojis.firstWhere(
(Emoji emoji) => emoji.char.contains(c),
orElse: () => null,
) !=
null;
});
return characters.every((c) => _emojis.map((e) => e.char).contains(c));
}
}
+122 -101
View File
@@ -174,117 +174,138 @@ class _ImageFooterState extends State<ImageFooter> {
showModalBottomSheet(
context: context,
barrierColor: StreamChatTheme.of(context).colorTheme.overlay,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: const BorderRadius.only(
topLeft: const Radius.circular(16.0),
topRight: const Radius.circular(16.0),
),
),
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
decoration: BoxDecoration(
color: StreamChatTheme.of(context).colorTheme.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(16.0),
topLeft: Radius.circular(16.0),
)),
child: Stack(
final crossAxisCount = 3;
final noOfRowToShowInitially =
widget.mediaAttachments.length > crossAxisCount ? 2 : 1;
final size = MediaQuery.of(context).size;
final initialChildSize =
48 + (size.width * noOfRowToShowInitially) / crossAxisCount;
return DraggableScrollableSheet(
expand: false,
initialChildSize: initialChildSize / size.height,
builder: (context, scrollController) {
return SingleChildScrollView(
controller: scrollController,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Photos',
style:
StreamChatTheme.of(context).textTheme.headlineBold,
Stack(
children: [
Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Photos',
style: StreamChatTheme.of(context)
.textTheme
.headlineBold,
),
),
),
),
Align(
alignment: Alignment.centerRight,
child: IconButton(
icon: StreamSvgIcon.close(
color: StreamChatTheme.of(context).colorTheme.black,
),
onPressed: () => Navigator.maybePop(context),
),
),
],
),
Align(
alignment: Alignment.centerRight,
child: IconButton(
icon: StreamSvgIcon.close(
color: StreamChatTheme.of(context).colorTheme.black,
Flexible(
child: GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: widget.mediaAttachments.length,
padding: const EdgeInsets.all(1),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
mainAxisSpacing: 2.0,
crossAxisSpacing: 2.0,
),
onPressed: () => Navigator.maybePop(context),
itemBuilder: (context, index) {
Widget media;
final attachment = widget.mediaAttachments[index];
if (attachment.type == 'video') {
var controllerPackage = widget.videoPackages[
videoAttachments.indexOf(attachment)];
media = InkWell(
onTap: () => widget.mediaSelectedCallBack(index),
child: FittedBox(
fit: BoxFit.cover,
child: Chewie(
controller: controllerPackage.chewieController,
),
),
);
} else {
media = InkWell(
onTap: () => widget.mediaSelectedCallBack(index),
child: AspectRatio(
child: CachedNetworkImage(
imageUrl: attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl,
fit: BoxFit.cover,
),
aspectRatio: 1.0,
),
);
}
return Stack(
children: [
media,
Padding(
padding: EdgeInsets.all(8.0),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: StreamChatTheme.of(context)
.colorTheme
.white
.withOpacity(0.6),
boxShadow: [
BoxShadow(
blurRadius: 8.0,
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.3),
),
],
),
padding: const EdgeInsets.all(1),
child: UserAvatar(
user: widget.message.user,
constraints:
BoxConstraints.tight(Size(24, 24)),
showOnlineStatus: false,
),
),
),
],
);
},
),
),
],
),
),
Container(
color: StreamChatTheme.of(context).colorTheme.white,
child: GridView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, position) {
Widget media;
if (widget.mediaAttachments[position].type == 'video') {
var controllerPackage = widget.videoPackages[
videoAttachments
.indexOf(widget.mediaAttachments[position])];
media = InkWell(
onTap: () {
widget.mediaSelectedCallBack(position);
},
child: FittedBox(
fit: BoxFit.cover,
child: Chewie(
controller: controllerPackage.chewieController,
),
),
);
} else {
media = InkWell(
onTap: () {
widget.mediaSelectedCallBack(position);
},
child: Padding(
padding: const EdgeInsets.all(1.0),
child: AspectRatio(
child: CachedNetworkImage(
imageUrl: widget
.mediaAttachments[position].imageUrl ??
widget.mediaAttachments[position].assetUrl ??
widget.mediaAttachments[position].thumbUrl,
fit: BoxFit.cover,
),
aspectRatio: 1.0,
),
),
);
}
return Stack(
children: [
media,
Padding(
padding: EdgeInsets.all(8.0),
child: Align(
alignment: Alignment.topLeft,
child: UserAvatar(
user: widget.message.user,
constraints: BoxConstraints.tight(
Size(
24,
24,
),
),
showOnlineStatus: false,
),
),
),
],
);
},
itemCount: widget.mediaAttachments.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
),
),
],
);
},
);
},
);
@@ -32,6 +32,7 @@ class MessageActionsModal extends StatefulWidget {
final bool showFlagButton;
final bool reverse;
final ShapeBorder messageShape;
final ShapeBorder attachmentShape;
final DisplayWidget showUserAvatar;
const MessageActionsModal({
@@ -51,6 +52,7 @@ class MessageActionsModal extends StatefulWidget {
this.showUserAvatar = DisplayWidget.show,
this.editMessageInputBuilder,
this.messageShape,
this.attachmentShape,
this.reverse = false,
}) : super(key: key);
@@ -173,6 +175,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
showInChannelIndicator: false,
showSendingIndicator: false,
shape: widget.messageShape,
attachmentShape: widget.attachmentShape,
),
),
SizedBox(height: 8),
@@ -461,7 +464,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
),
const SizedBox(width: 16),
Text(
'Flag',
'Flag Message',
style: StreamChatTheme.of(context).textTheme.body,
),
],
@@ -20,6 +20,7 @@ class MessageReactionsModal extends StatelessWidget {
final bool showReactions;
final DisplayWidget showUserAvatar;
final ShapeBorder messageShape;
final ShapeBorder attachmentShape;
final void Function(User) onUserAvatarTap;
const MessageReactionsModal({
@@ -30,6 +31,7 @@ class MessageReactionsModal extends StatelessWidget {
this.onThreadTap,
this.editMessageInputBuilder,
this.messageShape,
this.attachmentShape,
this.reverse = false,
this.showUserAvatar = DisplayWidget.show,
this.onUserAvatarTap,
@@ -127,6 +129,7 @@ class MessageReactionsModal extends StatelessWidget {
translateUserAvatar: false,
showSendingIndicator: false,
shape: messageShape,
attachmentShape: attachmentShape,
padding: const EdgeInsets.all(0),
attachmentPadding: EdgeInsets.all(
hasFileAttachment ? 4 : 2,
@@ -295,10 +295,6 @@ class _MessageWidgetState extends State<MessageWidget> {
var leftPadding =
widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5;
final hasFiles =
widget.message.attachments?.any((element) => element.type == 'file') ==
true;
return Material(
type: MaterialType.transparency,
child: Portal(
@@ -406,29 +402,19 @@ class _MessageWidgetState extends State<MessageWidget> {
BorderRadius.zero,
),
color: _getBackgroundColor(),
child: Padding(
padding: EdgeInsets.all(
hasFiles ? 2.0 : 0.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.end,
mainAxisSize:
MainAxisSize.min,
children: <Widget>[
if (hasQuotedMessage)
_buildQuotedMessage(),
if (hasNonUrlAttachments)
_parseAttachments(
context),
if (widget.message.text
.trim()
.isNotEmpty &&
!isGiphy)
_buildTextBubble(
context),
],
),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisSize:
MainAxisSize.min,
children: <Widget>[
if (hasQuotedMessage)
_buildQuotedMessage(),
if (hasNonUrlAttachments)
_parseAttachments(),
if (!isGiphy)
_buildTextBubble(),
],
),
),
),
@@ -536,7 +522,7 @@ class _MessageWidgetState extends State<MessageWidget> {
var children = <Widget>[];
final threadParticipants = widget.message.threadParticipants;
final threadParticipants = widget.message?.threadParticipants?.take(2);
final showThreadParticipants = threadParticipants?.isNotEmpty == true;
final replyCount = widget.message.replyCount;
@@ -565,7 +551,7 @@ class _MessageWidgetState extends State<MessageWidget> {
if (showThreadParticipants)
SizedBox.fromSize(
size: Size((threadParticipants.length * 8.0) + 8, 16),
child: _buildThreadParticipantsIndicator(),
child: _buildThreadParticipantsIndicator(threadParticipants),
),
InkWell(
onTap: widget.onThreadTap != null ? onThreadTap : null,
@@ -642,10 +628,10 @@ class _MessageWidgetState extends State<MessageWidget> {
);
}
Widget _buildThreadParticipantsIndicator() {
Widget _buildThreadParticipantsIndicator(Iterable<User> threadParticipants) {
var padding = 0.0;
return Stack(
children: widget.message.threadParticipants.map((user) {
children: threadParticipants.map((user) {
padding += 8.0;
return Positioned(
right: padding - 8,
@@ -718,6 +704,8 @@ class _MessageWidgetState extends State<MessageWidget> {
: DisplayWidget.show,
messageTheme: widget.messageTheme,
messageShape: widget.shape ?? _getDefaultShape(context),
attachmentShape:
widget.attachmentShape ?? _getDefaultAttachmentShape(context),
reverse: widget.reverse,
showDeleteMessage: widget.showDeleteMessage || isDeleteFailed,
message: widget.message,
@@ -763,6 +751,8 @@ class _MessageWidgetState extends State<MessageWidget> {
onUserAvatarTap: widget.onUserAvatarTap,
messageTheme: widget.messageTheme,
messageShape: widget.shape ?? _getDefaultShape(context),
attachmentShape:
widget.attachmentShape ?? _getDefaultAttachmentShape(context),
reverse: widget.reverse,
message: widget.message,
editMessageInputBuilder: widget.editMessageInputBuilder,
@@ -773,20 +763,31 @@ class _MessageWidgetState extends State<MessageWidget> {
});
}
ShapeBorder _getDefaultShape(BuildContext context) {
ShapeBorder _getDefaultAttachmentShape(BuildContext context) {
final hasFiles =
widget.message.attachments?.any((it) => it.type == 'file') == true;
return RoundedRectangleBorder(
side: widget.attachmentBorderSide ??
widget.borderSide ??
BorderSide(
color: StreamChatTheme.of(context).colorTheme.greyWhisper,
),
borderRadius: widget.attachmentBorderRadiusGeometry ??
widget.borderRadiusGeometry ??
BorderRadius.zero,
side: hasFiles
? widget.attachmentBorderSide ??
BorderSide(
color: StreamChatTheme.of(context).colorTheme.greyWhisper,
)
: BorderSide.none,
borderRadius: widget.attachmentBorderRadiusGeometry ?? BorderRadius.zero,
);
}
Widget _parseAttachments(BuildContext context) {
ShapeBorder _getDefaultShape(BuildContext context) {
return RoundedRectangleBorder(
side: widget.borderSide ??
BorderSide(
color: StreamChatTheme.of(context).colorTheme.greyWhisper,
),
borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero,
);
}
Widget _parseAttachments() {
final images = widget.message.attachments
?.where((element) =>
element.type == 'image' && element.ogScrapeUrl == null)
@@ -849,7 +850,7 @@ class _MessageWidgetState extends State<MessageWidget> {
Attachment attachment,
}) {
final attachmentShape =
widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context);
widget.attachmentShape ?? _getDefaultAttachmentShape(context);
return Material(
clipBehavior: Clip.antiAlias,
shape: attachmentShape,
@@ -920,7 +921,8 @@ class _MessageWidgetState extends State<MessageWidget> {
),
);
Widget _buildTextBubble(BuildContext context) {
Widget _buildTextBubble() {
if (widget.message.text.trim().isEmpty) return Offstage();
return Transform(
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
alignment: Alignment.center,
@@ -492,8 +492,8 @@ class ColorTheme {
),
this.borderTop = const Effect(
sigmaX: 0, sigmaY: -1, color: Color(0xff000000), blur: 0.0),
this.borderBottom =
const Effect(sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0),
this.borderBottom = const Effect(
sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0, alpha: 0.08),
this.shadowIconButton = const Effect(
sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0),
this.modalShadow = const Effect(
@@ -514,8 +514,8 @@ class ColorTheme {
this.accentGreen = const Color(0xff20E070),
this.borderTop = const Effect(
sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0.0),
this.borderBottom =
const Effect(sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0),
this.borderBottom = const Effect(
sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0, alpha: 1.0),
this.shadowIconButton = const Effect(
sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0),
this.modalShadow = const Effect(
@@ -416,6 +416,10 @@ class _UserListViewState extends State<UserListView>
height: 64,
width: 64,
),
onlineIndicatorConstraints: BoxConstraints.tightFor(
height: 12,
width: 12,
),
onTap: (user) =>
widget.onUserTap(user, widget.userWidget),
onLongPress: widget.onUserLongPress,