fix reaction bubble ui
This commit is contained in:
+66
-220
@@ -2,12 +2,13 @@ import 'dart:math';
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_portal/flutter_portal.dart';
|
import 'package:flutter_portal/flutter_portal.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:jiffy/jiffy.dart';
|
import 'package:jiffy/jiffy.dart';
|
||||||
import 'package:stream_chat_flutter/src/message_actions_modal.dart';
|
import 'package:stream_chat_flutter/src/message_actions_modal.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import 'image_group.dart';
|
import 'image_group.dart';
|
||||||
@@ -198,9 +199,6 @@ class MessageWidget extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MessageWidgetState extends State<MessageWidget> {
|
class _MessageWidgetState extends State<MessageWidget> {
|
||||||
final GlobalKey _reactionPickerKey = GlobalKey();
|
|
||||||
double _reactionPadding = 0;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var leftPadding = widget.showUserAvatar != DisplayWidget.gone
|
var leftPadding = widget.showUserAvatar != DisplayWidget.gone
|
||||||
@@ -243,11 +241,15 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: widget.showReactions
|
padding: widget.showReactions
|
||||||
? EdgeInsets.only(
|
? EdgeInsets.only(
|
||||||
top: _reactionPadding,
|
top: widget.message.reactionCounts
|
||||||
|
?.isNotEmpty ==
|
||||||
|
true
|
||||||
|
? 16
|
||||||
|
: 0,
|
||||||
)
|
)
|
||||||
: EdgeInsets.zero,
|
: EdgeInsets.zero,
|
||||||
child: PortalEntry(
|
child: PortalEntry(
|
||||||
portalAnchor: Alignment(0, 1),
|
portalAnchor: Alignment(-0.81, 0),
|
||||||
childAnchor: Alignment.topRight,
|
childAnchor: Alignment.topRight,
|
||||||
portal: _buildReactionIndicator(context),
|
portal: _buildReactionIndicator(context),
|
||||||
child: (widget.message.isDeleted &&
|
child: (widget.message.isDeleted &&
|
||||||
@@ -296,57 +298,6 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void didUpdateWidget(MessageWidget oldWidget) {
|
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
_updateReactionPadding();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_updateReactionPadding();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateReactionPadding() {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
|
||||||
if (!mounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_reactionPickerKey.currentContext != null &&
|
|
||||||
widget.message.reactionCounts != null &&
|
|
||||||
widget.message.reactionCounts.values
|
|
||||||
.where((element) => element > 0)
|
|
||||||
.isNotEmpty) {
|
|
||||||
setState(() {
|
|
||||||
_reactionPadding = _reactionPickerKey.currentContext.size.height;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setState(() {
|
|
||||||
_reactionPadding = 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildReactionsTail(BuildContext context) {
|
|
||||||
return AnimatedSwitcher(
|
|
||||||
duration: Duration(milliseconds: 300),
|
|
||||||
child: widget.message.reactionCounts?.isNotEmpty == true
|
|
||||||
? Transform.translate(
|
|
||||||
offset: Offset(4, 0),
|
|
||||||
child: CustomPaint(
|
|
||||||
painter: ReactionBubblePainter(
|
|
||||||
widget.messageTheme.reactionsBackgroundColor,
|
|
||||||
widget.messageTheme.reactionsBorderColor,
|
|
||||||
widget.message.reactionCounts.length,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: SizedBox(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Padding _buildBottomRow(double leftPadding) {
|
Padding _buildBottomRow(double leftPadding) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
@@ -427,53 +378,72 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildReactionIndicator(BuildContext context) {
|
Widget _buildReactionIndicator(BuildContext context) {
|
||||||
|
final otherReactions = widget.message.latestReactions
|
||||||
|
?.where(
|
||||||
|
(element) => element.user.id != StreamChat.of(context).user.id)
|
||||||
|
?.toList() ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
var rowChildren = [
|
||||||
|
if (widget.message.ownReactions?.isNotEmpty == true) ...[
|
||||||
|
Transform.translate(
|
||||||
|
offset: Offset(
|
||||||
|
widget.reverse ? -6 : 0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
child: ReactionBubble(
|
||||||
|
key: ValueKey('${widget.message.id}.own'),
|
||||||
|
reverse: widget.reverse,
|
||||||
|
backgroundColor: widget.messageTheme.ownReactionsBackgroundColor,
|
||||||
|
borderColor: widget.messageTheme.ownReactionsBorderColor,
|
||||||
|
reactions: widget.message.ownReactions,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (otherReactions.isEmpty)
|
||||||
|
Container(
|
||||||
|
width: 18,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
if (otherReactions?.isNotEmpty == true) ...[
|
||||||
|
if (widget.message.ownReactions?.isEmpty == true)
|
||||||
|
Container(
|
||||||
|
width: 18,
|
||||||
|
),
|
||||||
|
Transform.translate(
|
||||||
|
offset: Offset(
|
||||||
|
widget.reverse ? 0 : -6,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
child: ReactionBubble(
|
||||||
|
key: ValueKey('${widget.message.id}.other'),
|
||||||
|
reactions: otherReactions,
|
||||||
|
reverse: widget.reverse,
|
||||||
|
flipTail: true,
|
||||||
|
backgroundColor: widget.messageTheme.otherReactionsBackgroundColor,
|
||||||
|
borderColor: widget.messageTheme.otherReactionsBorderColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
if (widget.reverse) {
|
||||||
|
rowChildren = rowChildren.reversed.toList();
|
||||||
|
}
|
||||||
return AnimatedSwitcher(
|
return AnimatedSwitcher(
|
||||||
key: _reactionPickerKey,
|
|
||||||
duration: Duration(milliseconds: 300),
|
duration: Duration(milliseconds: 300),
|
||||||
child: (widget.showReactions &&
|
child: (widget.showReactions &&
|
||||||
widget.message.reactionCounts?.isNotEmpty == true &&
|
(widget.message.reactionCounts?.isNotEmpty == true ||
|
||||||
|
otherReactions.isNotEmpty) &&
|
||||||
!widget.message.isDeleted)
|
!widget.message.isDeleted)
|
||||||
? Container(
|
? Container(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => onLongPress(context),
|
onTap: () => onLongPress(context),
|
||||||
child: FractionallySizedBox(
|
child: FractionallySizedBox(
|
||||||
widthFactor: 0.3,
|
widthFactor: 0.5,
|
||||||
child: Padding(
|
child: Row(
|
||||||
padding: const EdgeInsets.only(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
bottom: 4.0,
|
mainAxisSize: MainAxisSize.min,
|
||||||
),
|
children: rowChildren,
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Transform(
|
|
||||||
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: widget.messageTheme
|
|
||||||
.reactionsBackgroundColor ==
|
|
||||||
StreamChatTheme.of(context)
|
|
||||||
.backgroundColor
|
|
||||||
? Border.all(
|
|
||||||
color: Theme.of(context).brightness ==
|
|
||||||
Brightness.dark
|
|
||||||
? Colors.white.withAlpha(24)
|
|
||||||
: Colors.black.withAlpha(24),
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
color:
|
|
||||||
widget.messageTheme.reactionsBackgroundColor,
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.all(Radius.circular(14)),
|
|
||||||
),
|
|
||||||
child: _buildReactions(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_buildReactionsTail(context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -482,36 +452,6 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildReactions(BuildContext context) {
|
|
||||||
final reactionAssets = StreamChatTheme.of(context).reactionAssets;
|
|
||||||
return Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
...widget.message.reactionCounts.keys.map((reactionType) {
|
|
||||||
final reactionAsset = reactionAssets.firstWhere(
|
|
||||||
(reactionAsset) => reactionAsset.type == reactionType,
|
|
||||||
orElse: () => null,
|
|
||||||
);
|
|
||||||
if (reactionAsset == null) {
|
|
||||||
return Text(
|
|
||||||
'?',
|
|
||||||
style: TextStyle(
|
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SvgPicture.asset(
|
|
||||||
reactionAsset.svgAsset,
|
|
||||||
package: reactionAsset.package,
|
|
||||||
height: 16,
|
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showMessageModalBottomSheet(BuildContext context) {
|
void _showMessageModalBottomSheet(BuildContext context) {
|
||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
showDialog(
|
showDialog(
|
||||||
@@ -825,97 +765,3 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReactionBubblePainter extends CustomPainter {
|
|
||||||
final Color color;
|
|
||||||
final Color borderColor;
|
|
||||||
final int reactionsCount;
|
|
||||||
|
|
||||||
ReactionBubblePainter(
|
|
||||||
this.color,
|
|
||||||
this.borderColor,
|
|
||||||
this.reactionsCount,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void paint(Canvas canvas, Size size) {
|
|
||||||
_drawArc(size, canvas);
|
|
||||||
|
|
||||||
_drawBorder(size, canvas);
|
|
||||||
|
|
||||||
_drawOval(size, canvas);
|
|
||||||
|
|
||||||
_drawOvalBorder(size, canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _drawOvalBorder(Size size, Canvas canvas) {
|
|
||||||
final paint = Paint()
|
|
||||||
..color = borderColor
|
|
||||||
..strokeWidth = 1
|
|
||||||
..style = PaintingStyle.stroke;
|
|
||||||
|
|
||||||
final path = Path();
|
|
||||||
path.addOval(
|
|
||||||
Rect.fromCircle(
|
|
||||||
center: Offset(0, 3),
|
|
||||||
radius: 2,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _drawOval(Size size, Canvas canvas) {
|
|
||||||
final paint = Paint()
|
|
||||||
..color = color
|
|
||||||
..strokeWidth = 1;
|
|
||||||
|
|
||||||
final path = Path();
|
|
||||||
path.addOval(Rect.fromCircle(
|
|
||||||
center: Offset(0, 3),
|
|
||||||
radius: 2,
|
|
||||||
));
|
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _drawBorder(Size size, Canvas canvas) {
|
|
||||||
final paint = Paint()
|
|
||||||
..color = borderColor
|
|
||||||
..strokeWidth = 1
|
|
||||||
..style = PaintingStyle.stroke;
|
|
||||||
|
|
||||||
final dy = reactionsCount > 1 ? -2.0 : -3.0;
|
|
||||||
final path = Path();
|
|
||||||
path.addArc(
|
|
||||||
Rect.fromCircle(
|
|
||||||
center: Offset(-4, dy),
|
|
||||||
radius: 4,
|
|
||||||
),
|
|
||||||
-pi * 1.15,
|
|
||||||
-pi / 1.4,
|
|
||||||
);
|
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _drawArc(Size size, Canvas canvas) {
|
|
||||||
final paint = Paint()
|
|
||||||
..color = color
|
|
||||||
..strokeWidth = 1;
|
|
||||||
|
|
||||||
final dy = reactionsCount > 1 ? -2.0 : -3.0;
|
|
||||||
final path = Path();
|
|
||||||
path.addArc(
|
|
||||||
Rect.fromCircle(
|
|
||||||
center: Offset(-4, dy),
|
|
||||||
radius: 4,
|
|
||||||
),
|
|
||||||
-pi,
|
|
||||||
-pi,
|
|
||||||
);
|
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRepaint(CustomPainter oldDelegate) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
class ReactionBubble extends StatelessWidget {
|
||||||
|
const ReactionBubble({
|
||||||
|
Key key,
|
||||||
|
@required this.reactions,
|
||||||
|
@required this.borderColor,
|
||||||
|
@required this.backgroundColor,
|
||||||
|
this.reverse = false,
|
||||||
|
this.flipTail = false,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final List<Reaction> reactions;
|
||||||
|
final Color borderColor;
|
||||||
|
final Color backgroundColor;
|
||||||
|
final bool reverse;
|
||||||
|
final bool flipTail;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final reactionAssets = StreamChatTheme.of(context).reactionAssets;
|
||||||
|
return Transform(
|
||||||
|
transform: Matrix4.rotationY(reverse ? pi : 0),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: borderColor,
|
||||||
|
),
|
||||||
|
color: backgroundColor,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||||
|
),
|
||||||
|
child: Wrap(
|
||||||
|
children: [
|
||||||
|
...reactions.map((reaction) {
|
||||||
|
final reactionAsset = reactionAssets.firstWhere(
|
||||||
|
(reactionAsset) => reactionAsset.type == reaction.type,
|
||||||
|
orElse: () => null,
|
||||||
|
);
|
||||||
|
if (reactionAsset == null) {
|
||||||
|
return Text(
|
||||||
|
'?',
|
||||||
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context).accentColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SvgPicture.asset(
|
||||||
|
reactionAsset.svgAsset,
|
||||||
|
package: reactionAsset.package,
|
||||||
|
height: 16,
|
||||||
|
color: StreamChatTheme.of(context).accentColor,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_buildReactionsTail(context),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildReactionsTail(BuildContext context) {
|
||||||
|
final tail = Transform.translate(
|
||||||
|
offset: Offset(4, 0),
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: ReactionBubblePainter(
|
||||||
|
backgroundColor,
|
||||||
|
borderColor,
|
||||||
|
reactions.length,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!flipTail) {
|
||||||
|
return tail;
|
||||||
|
} else {
|
||||||
|
return Transform(
|
||||||
|
transform: Matrix4.rotationY(pi),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: tail,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReactionBubblePainter extends CustomPainter {
|
||||||
|
final Color color;
|
||||||
|
final Color borderColor;
|
||||||
|
final int reactionsCount;
|
||||||
|
|
||||||
|
ReactionBubblePainter(
|
||||||
|
this.color,
|
||||||
|
this.borderColor,
|
||||||
|
this.reactionsCount,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
_drawOval(size, canvas);
|
||||||
|
|
||||||
|
_drawOvalBorder(size, canvas);
|
||||||
|
|
||||||
|
_drawArc(size, canvas);
|
||||||
|
|
||||||
|
_drawBorder(size, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawOvalBorder(Size size, Canvas canvas) {
|
||||||
|
final paint = Paint()
|
||||||
|
..color = borderColor
|
||||||
|
..strokeWidth = 1
|
||||||
|
..style = PaintingStyle.stroke;
|
||||||
|
|
||||||
|
final path = Path();
|
||||||
|
path.addOval(
|
||||||
|
Rect.fromCircle(
|
||||||
|
center: Offset(6, 2),
|
||||||
|
radius: 2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
canvas.drawPath(path, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawOval(Size size, Canvas canvas) {
|
||||||
|
final paint = Paint()
|
||||||
|
..color = color
|
||||||
|
..strokeWidth = 1;
|
||||||
|
|
||||||
|
final path = Path();
|
||||||
|
path.addOval(Rect.fromCircle(
|
||||||
|
center: Offset(6, 2),
|
||||||
|
radius: 2,
|
||||||
|
));
|
||||||
|
canvas.drawPath(path, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawBorder(Size size, Canvas canvas) {
|
||||||
|
final paint = Paint()
|
||||||
|
..color = borderColor
|
||||||
|
..strokeWidth = 1
|
||||||
|
..style = PaintingStyle.stroke;
|
||||||
|
|
||||||
|
final dy = reactionsCount > 1 ? -2.0 : -3.0;
|
||||||
|
final startAngle = reactionsCount > 1 ? 1.08 : 1.16;
|
||||||
|
final sweepAngle = reactionsCount > 1 ? 1.18 : 1.1;
|
||||||
|
final path = Path();
|
||||||
|
path.addArc(
|
||||||
|
Rect.fromCircle(
|
||||||
|
center: Offset(0, dy),
|
||||||
|
radius: 4,
|
||||||
|
),
|
||||||
|
-pi * startAngle,
|
||||||
|
-pi / sweepAngle,
|
||||||
|
);
|
||||||
|
canvas.drawPath(path, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawArc(Size size, Canvas canvas) {
|
||||||
|
final paint = Paint()
|
||||||
|
..color = color
|
||||||
|
..strokeWidth = 1;
|
||||||
|
|
||||||
|
final dy = reactionsCount > 1 ? -2.0 : -3.0;
|
||||||
|
final startAngle = reactionsCount > 1 ? 1.05 : 1.16;
|
||||||
|
final path = Path();
|
||||||
|
path.addArc(
|
||||||
|
Rect.fromCircle(
|
||||||
|
center: Offset(0, dy),
|
||||||
|
radius: 4,
|
||||||
|
),
|
||||||
|
-pi * startAngle,
|
||||||
|
-pi,
|
||||||
|
);
|
||||||
|
canvas.drawPath(path, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(CustomPainter oldDelegate) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ class ReactionPicker extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final reactionAssets = StreamChatTheme.of(context).reactionAssets;
|
final reactionAssets = StreamChatTheme.of(context).reactionAssets;
|
||||||
return Material(
|
return Material(
|
||||||
color: messageTheme.reactionsBackgroundColor,
|
color: messageTheme.ownReactionsBackgroundColor,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
@@ -35,7 +35,7 @@ class ReactionPicker extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: reactionAssets.map((reactionAsset) {
|
children: reactionAssets.map((reactionAsset) {
|
||||||
final ownReactionIndex = message.latestReactions?.indexWhere(
|
final ownReactionIndex = message.ownReactions?.indexWhere(
|
||||||
(reaction) => reaction.type == reactionAsset.type) ??
|
(reaction) => reaction.type == reactionAsset.type) ??
|
||||||
-1;
|
-1;
|
||||||
return IconButton(
|
return IconButton(
|
||||||
@@ -45,7 +45,7 @@ class ReactionPicker extends StatelessWidget {
|
|||||||
package: reactionAsset.package,
|
package: reactionAsset.package,
|
||||||
color: ownReactionIndex != -1
|
color: ownReactionIndex != -1
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).accentColor
|
||||||
: Colors.black,
|
: Theme.of(context).iconTheme.color,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (ownReactionIndex != -1) {
|
if (ownReactionIndex != -1) {
|
||||||
|
|||||||
@@ -81,7 +81,9 @@ class StreamChannelState extends State<StreamChannel> {
|
|||||||
}
|
}
|
||||||
_queryMessageController.add(false);
|
_queryMessageController.add(false);
|
||||||
}).catchError((e, stack) {
|
}).catchError((e, stack) {
|
||||||
_queryMessageController.addError(e, stack);
|
if (!_queryMessageController.isClosed) {
|
||||||
|
_queryMessageController.addError(e, stack);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,14 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
|||||||
constraints: themeData?.ownMessageTheme?.avatarTheme?.constraints,
|
constraints: themeData?.ownMessageTheme?.avatarTheme?.constraints,
|
||||||
borderRadius: themeData?.ownMessageTheme?.avatarTheme?.borderRadius,
|
borderRadius: themeData?.ownMessageTheme?.avatarTheme?.borderRadius,
|
||||||
),
|
),
|
||||||
|
otherReactionsBorderColor:
|
||||||
|
themeData?.ownMessageTheme?.otherReactionsBorderColor,
|
||||||
|
otherReactionsBackgroundColor:
|
||||||
|
themeData?.ownMessageTheme?.otherReactionsBackgroundColor,
|
||||||
|
ownReactionsBackgroundColor:
|
||||||
|
themeData?.ownMessageTheme?.ownReactionsBackgroundColor,
|
||||||
|
ownReactionsBorderColor:
|
||||||
|
themeData?.ownMessageTheme?.ownReactionsBorderColor,
|
||||||
),
|
),
|
||||||
otherMessageTheme: defaultTheme.otherMessageTheme.copyWith(
|
otherMessageTheme: defaultTheme.otherMessageTheme.copyWith(
|
||||||
replies: themeData?.otherMessageTheme?.replies,
|
replies: themeData?.otherMessageTheme?.replies,
|
||||||
@@ -142,6 +150,14 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
|||||||
constraints: themeData?.otherMessageTheme?.avatarTheme?.constraints,
|
constraints: themeData?.otherMessageTheme?.avatarTheme?.constraints,
|
||||||
borderRadius: themeData?.otherMessageTheme?.avatarTheme?.borderRadius,
|
borderRadius: themeData?.otherMessageTheme?.avatarTheme?.borderRadius,
|
||||||
),
|
),
|
||||||
|
otherReactionsBorderColor:
|
||||||
|
themeData?.otherMessageTheme?.otherReactionsBorderColor,
|
||||||
|
otherReactionsBackgroundColor:
|
||||||
|
themeData?.otherMessageTheme?.otherReactionsBackgroundColor,
|
||||||
|
ownReactionsBackgroundColor:
|
||||||
|
themeData?.otherMessageTheme?.ownReactionsBackgroundColor,
|
||||||
|
ownReactionsBorderColor:
|
||||||
|
themeData?.otherMessageTheme?.ownReactionsBorderColor,
|
||||||
),
|
),
|
||||||
accentColor: themeData?.accentColor,
|
accentColor: themeData?.accentColor,
|
||||||
secondaryColor: themeData?.secondaryColor,
|
secondaryColor: themeData?.secondaryColor,
|
||||||
|
|||||||
@@ -302,8 +302,12 @@ class StreamChatThemeData {
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
||||||
reactionsBackgroundColor: isDark ? Colors.black : Colors.white,
|
ownReactionsBackgroundColor:
|
||||||
reactionsBorderColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
||||||
|
ownReactionsBorderColor: isDark ? Colors.black : Colors.white,
|
||||||
|
otherReactionsBackgroundColor: isDark ? Colors.black : Colors.white,
|
||||||
|
otherReactionsBorderColor:
|
||||||
|
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarTheme(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
@@ -316,9 +320,12 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
otherMessageTheme: MessageTheme(
|
otherMessageTheme: MessageTheme(
|
||||||
reactionsBackgroundColor:
|
ownReactionsBackgroundColor:
|
||||||
|
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
||||||
|
ownReactionsBorderColor: isDark ? Colors.black : Colors.white,
|
||||||
|
otherReactionsBackgroundColor: isDark ? Colors.black : Colors.white,
|
||||||
|
otherReactionsBorderColor:
|
||||||
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
||||||
reactionsBorderColor: theme.scaffoldBackgroundColor,
|
|
||||||
messageText: TextStyle(
|
messageText: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
color: isDark ? Colors.white : Colors.black,
|
color: isDark ? Colors.white : Colors.black,
|
||||||
@@ -455,8 +462,10 @@ class MessageTheme {
|
|||||||
final TextStyle createdAt;
|
final TextStyle createdAt;
|
||||||
final TextStyle replies;
|
final TextStyle replies;
|
||||||
final Color messageBackgroundColor;
|
final Color messageBackgroundColor;
|
||||||
final Color reactionsBackgroundColor;
|
final Color ownReactionsBackgroundColor;
|
||||||
final Color reactionsBorderColor;
|
final Color ownReactionsBorderColor;
|
||||||
|
final Color otherReactionsBackgroundColor;
|
||||||
|
final Color otherReactionsBorderColor;
|
||||||
final AvatarTheme avatarTheme;
|
final AvatarTheme avatarTheme;
|
||||||
|
|
||||||
const MessageTheme({
|
const MessageTheme({
|
||||||
@@ -465,8 +474,10 @@ class MessageTheme {
|
|||||||
this.messageAuthor,
|
this.messageAuthor,
|
||||||
this.messageLinks,
|
this.messageLinks,
|
||||||
this.messageBackgroundColor,
|
this.messageBackgroundColor,
|
||||||
this.reactionsBackgroundColor,
|
this.ownReactionsBackgroundColor,
|
||||||
this.reactionsBorderColor,
|
this.ownReactionsBorderColor,
|
||||||
|
this.otherReactionsBackgroundColor,
|
||||||
|
this.otherReactionsBorderColor,
|
||||||
this.avatarTheme,
|
this.avatarTheme,
|
||||||
this.createdAt,
|
this.createdAt,
|
||||||
});
|
});
|
||||||
@@ -478,10 +489,11 @@ class MessageTheme {
|
|||||||
TextStyle createdAt,
|
TextStyle createdAt,
|
||||||
TextStyle replies,
|
TextStyle replies,
|
||||||
Color messageBackgroundColor,
|
Color messageBackgroundColor,
|
||||||
Color otherMessageBackgroundColor,
|
|
||||||
AvatarTheme avatarTheme,
|
AvatarTheme avatarTheme,
|
||||||
Color reactionsBackgroundColor,
|
Color ownReactionsBackgroundColor,
|
||||||
Color reactionsBorderColor,
|
Color ownReactionsBorderColor,
|
||||||
|
Color otherReactionsBackgroundColor,
|
||||||
|
Color otherReactionsBorderColor,
|
||||||
}) =>
|
}) =>
|
||||||
MessageTheme(
|
MessageTheme(
|
||||||
messageText: messageText ?? this.messageText,
|
messageText: messageText ?? this.messageText,
|
||||||
@@ -492,9 +504,14 @@ class MessageTheme {
|
|||||||
messageBackgroundColor ?? this.messageBackgroundColor,
|
messageBackgroundColor ?? this.messageBackgroundColor,
|
||||||
avatarTheme: avatarTheme ?? this.avatarTheme,
|
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||||
replies: replies ?? this.replies,
|
replies: replies ?? this.replies,
|
||||||
reactionsBackgroundColor:
|
ownReactionsBackgroundColor:
|
||||||
reactionsBackgroundColor ?? this.reactionsBackgroundColor,
|
ownReactionsBackgroundColor ?? this.ownReactionsBackgroundColor,
|
||||||
reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor,
|
ownReactionsBorderColor:
|
||||||
|
ownReactionsBorderColor ?? this.ownReactionsBorderColor,
|
||||||
|
otherReactionsBackgroundColor:
|
||||||
|
otherReactionsBackgroundColor ?? this.otherReactionsBackgroundColor,
|
||||||
|
otherReactionsBorderColor:
|
||||||
|
otherReactionsBorderColor ?? this.otherReactionsBorderColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ dependencies:
|
|||||||
image_picker: ^0.6.7+2
|
image_picker: ^0.6.7+2
|
||||||
flutter_keyboard_visibility: ^3.2.1
|
flutter_keyboard_visibility: ^3.2.1
|
||||||
flutter_svg: ^0.18.0
|
flutter_svg: ^0.18.0
|
||||||
stream_chat: ^0.2.7+1
|
stream_chat: ^0.2.8
|
||||||
mime: ^0.9.6+3
|
mime: ^0.9.6+3
|
||||||
visibility_detector: ^0.1.5
|
visibility_detector: ^0.1.5
|
||||||
line_awesome_icons: ^1.0.4+2
|
line_awesome_icons: ^1.0.4+2
|
||||||
|
|||||||
Reference in New Issue
Block a user