Merge branch 'master' into feature/notifications
This commit is contained in:
@@ -1,3 +1,15 @@
|
|||||||
|
## 0.1.17
|
||||||
|
|
||||||
|
- Add dark theme
|
||||||
|
|
||||||
|
## 0.1.16
|
||||||
|
|
||||||
|
- Add possibility to show the other users username next to the message timestamp
|
||||||
|
|
||||||
|
## 0.1.15
|
||||||
|
|
||||||
|
- Fix MessageInput overflow
|
||||||
|
|
||||||
## 0.1.14
|
## 0.1.14
|
||||||
|
|
||||||
- Add automatic keep alive to streamchat
|
- Add automatic keep alive to streamchat
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ The example is available under the [example](https://github.com/GetStream/stream
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
dependencies:
|
dependencies:
|
||||||
stream_chat_flutter: ^0.1.13
|
stream_chat_flutter: ^0.1.15
|
||||||
```
|
```
|
||||||
|
|
||||||
You should then run `flutter packages get`
|
You should then run `flutter packages get`
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ class MyApp extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
theme: ThemeData.light(),
|
||||||
|
darkTheme: ThemeData.dark(),
|
||||||
|
themeMode: ThemeMode.system,
|
||||||
home: Container(
|
home: Container(
|
||||||
child: StreamChat(
|
child: StreamChat(
|
||||||
client: client,
|
client: client,
|
||||||
|
|||||||
@@ -136,12 +136,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fillColor: Colors.black.withOpacity(.1),
|
fillColor: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white.withOpacity(.1)
|
||||||
|
: Colors.black.withOpacity(.1),
|
||||||
padding: EdgeInsets.all(4),
|
padding: EdgeInsets.all(4),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.arrow_back_ios,
|
Icons.arrow_back_ios,
|
||||||
size: 15,
|
size: 15,
|
||||||
color: Colors.black,
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -315,7 +315,9 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
Widget _separatorBuilder(context, i) {
|
Widget _separatorBuilder(context, i) {
|
||||||
return Container(
|
return Container(
|
||||||
height: 1,
|
height: 1,
|
||||||
color: Colors.black.withOpacity(0.1),
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white.withOpacity(0.1)
|
||||||
|
: Colors.black.withOpacity(0.1),
|
||||||
margin: EdgeInsets.symmetric(horizontal: 16),
|
margin: EdgeInsets.symmetric(horizontal: 16),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+69
-53
@@ -56,12 +56,13 @@ import 'stream_channel.dart';
|
|||||||
/// The widget renders the ui based on the first ancestor of type [StreamChatTheme].
|
/// The widget renders the ui based on the first ancestor of type [StreamChatTheme].
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class MessageInput extends StatefulWidget {
|
class MessageInput extends StatefulWidget {
|
||||||
MessageInput({
|
MessageInput(
|
||||||
Key key,
|
{Key key,
|
||||||
this.onMessageSent,
|
this.onMessageSent,
|
||||||
this.parentMessage,
|
this.parentMessage,
|
||||||
this.editMessage,
|
this.editMessage,
|
||||||
}) : super(key: key);
|
this.maxHeight = 150})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
/// Message to edit
|
/// Message to edit
|
||||||
final Message editMessage;
|
final Message editMessage;
|
||||||
@@ -72,6 +73,9 @@ class MessageInput extends StatefulWidget {
|
|||||||
/// Parent message in case of a thread
|
/// Parent message in case of a thread
|
||||||
final Message parentMessage;
|
final Message parentMessage;
|
||||||
|
|
||||||
|
/// Maximum Height for the TextField to grow before it starts scrolling
|
||||||
|
final double maxHeight;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageInputState createState() => _MessageInputState();
|
_MessageInputState createState() => _MessageInputState();
|
||||||
}
|
}
|
||||||
@@ -111,6 +115,7 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
Flex _buildTextField(BuildContext context) {
|
Flex _buildTextField(BuildContext context) {
|
||||||
return Flex(
|
return Flex(
|
||||||
direction: Axis.horizontal,
|
direction: Axis.horizontal,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
_buildAttachmentButton(),
|
_buildAttachmentButton(),
|
||||||
_buildTextInput(context),
|
_buildTextInput(context),
|
||||||
@@ -133,54 +138,57 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
|
|
||||||
Expanded _buildTextInput(BuildContext context) {
|
Expanded _buildTextInput(BuildContext context) {
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: TextField(
|
child: LimitedBox(
|
||||||
key: Key('messageInputText'),
|
maxHeight: widget.maxHeight,
|
||||||
minLines: null,
|
child: TextField(
|
||||||
maxLines: null,
|
key: Key('messageInputText'),
|
||||||
onSubmitted: (_) {
|
minLines: null,
|
||||||
_sendMessage(context);
|
maxLines: null,
|
||||||
},
|
onSubmitted: (_) {
|
||||||
controller: _textController,
|
_sendMessage(context);
|
||||||
focusNode: _focusNode,
|
},
|
||||||
onChanged: (s) {
|
controller: _textController,
|
||||||
StreamChannel.of(context).channel.keyStroke();
|
focusNode: _focusNode,
|
||||||
|
onChanged: (s) {
|
||||||
|
StreamChannel.of(context).channel.keyStroke();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_messageIsPresent = s.trim().isNotEmpty;
|
_messageIsPresent = s.trim().isNotEmpty;
|
||||||
});
|
});
|
||||||
|
|
||||||
_commandsOverlay?.remove();
|
_commandsOverlay?.remove();
|
||||||
_commandsOverlay = null;
|
_commandsOverlay = null;
|
||||||
_mentionsOverlay?.remove();
|
_mentionsOverlay?.remove();
|
||||||
_mentionsOverlay = null;
|
_mentionsOverlay = null;
|
||||||
|
|
||||||
if (s.startsWith('/')) {
|
if (s.startsWith('/')) {
|
||||||
_commandsOverlay = _buildCommandsOverlayEntry();
|
_commandsOverlay = _buildCommandsOverlayEntry();
|
||||||
Overlay.of(context).insert(_commandsOverlay);
|
Overlay.of(context).insert(_commandsOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_textController.selection.isCollapsed &&
|
if (_textController.selection.isCollapsed &&
|
||||||
(s[_textController.selection.start - 1] == '@' ||
|
(s[_textController.selection.start - 1] == '@' ||
|
||||||
_textController.text
|
_textController.text
|
||||||
.substring(0, _textController.selection.start)
|
.substring(0, _textController.selection.start)
|
||||||
.split(' ')
|
.split(' ')
|
||||||
.last
|
.last
|
||||||
.contains('@'))) {
|
.contains('@'))) {
|
||||||
_mentionsOverlay = _buildMentionsOverlayEntry();
|
_mentionsOverlay = _buildMentionsOverlayEntry();
|
||||||
Overlay.of(context).insert(_mentionsOverlay);
|
Overlay.of(context).insert(_mentionsOverlay);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_typingStarted = true;
|
_typingStarted = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
style: Theme.of(context).textTheme.body1,
|
style: Theme.of(context).textTheme.body1,
|
||||||
autofocus: false,
|
autofocus: false,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Write a message',
|
hintText: 'Write a message',
|
||||||
prefixText: ' ',
|
prefixText: ' ',
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -197,7 +205,10 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context)
|
||||||
|
.channelTheme
|
||||||
|
.inputBackground
|
||||||
|
.withAlpha(255),
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
@@ -207,7 +218,9 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: _typingStarted
|
color: _typingStarted
|
||||||
? Colors.transparent
|
? Colors.transparent
|
||||||
: Colors.black.withOpacity(.2)),
|
: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white.withOpacity(.2)
|
||||||
|
: Colors.black.withOpacity(.2)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -775,7 +788,10 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
if (attachment.type == 'image') {
|
if (attachment.type == 'image') {
|
||||||
_attachments.add(_SendingAttachment(
|
_attachments.add(_SendingAttachment(
|
||||||
type: FileType.image,
|
type: FileType.image,
|
||||||
url: attachment.imageUrl,
|
url: attachment.imageUrl ??
|
||||||
|
attachment.assetUrl ??
|
||||||
|
attachment.thumbUrl ??
|
||||||
|
attachment.ogScrapeUrl,
|
||||||
uploaded: true,
|
uploaded: true,
|
||||||
));
|
));
|
||||||
} else if (attachment.type == 'video') {
|
} else if (attachment.type == 'video') {
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class MessageListView extends StatefulWidget {
|
|||||||
this.parentMessage,
|
this.parentMessage,
|
||||||
this.threadBuilder,
|
this.threadBuilder,
|
||||||
this.onThreadTap,
|
this.onThreadTap,
|
||||||
|
this.showOtherMessageUsername = false,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// Function used to build a custom message widget
|
/// Function used to build a custom message widget
|
||||||
@@ -79,6 +80,9 @@ class MessageListView extends StatefulWidget {
|
|||||||
/// Parent message in case of a thread
|
/// Parent message in case of a thread
|
||||||
final Message parentMessage;
|
final Message parentMessage;
|
||||||
|
|
||||||
|
/// If true show the other users username next to the timestamp of the message
|
||||||
|
final bool showOtherMessageUsername;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageListViewState createState() => _MessageListViewState();
|
_MessageListViewState createState() => _MessageListViewState();
|
||||||
}
|
}
|
||||||
@@ -142,7 +146,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
'Start of thread',
|
'Start of thread',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
color: Theme.of(context).primaryColorLight,
|
color: Theme.of(context).accentColor.withAlpha(50),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -193,6 +197,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
message: message,
|
message: message,
|
||||||
nextMessage: nextMessage,
|
nextMessage: nextMessage,
|
||||||
onThreadTap: _onThreadTap,
|
onThreadTap: _onThreadTap,
|
||||||
|
showOtherMessageUsername: widget.showOtherMessageUsername,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: _messages.length + 2,
|
childCount: _messages.length + 2,
|
||||||
|
|||||||
+114
-22
@@ -41,6 +41,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
this.onMessageActions,
|
this.onMessageActions,
|
||||||
this.isParent = false,
|
this.isParent = false,
|
||||||
this.onMentionTap,
|
this.onMentionTap,
|
||||||
|
this.showOtherMessageUsername = false,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// Function called on mention tap
|
/// Function called on mention tap
|
||||||
@@ -49,6 +50,9 @@ class MessageWidget extends StatefulWidget {
|
|||||||
/// Function called on long press
|
/// Function called on long press
|
||||||
final Function(BuildContext, Message) onMessageActions;
|
final Function(BuildContext, Message) onMessageActions;
|
||||||
|
|
||||||
|
/// If true show the other users username next to the timestamp of the message
|
||||||
|
final bool showOtherMessageUsername;
|
||||||
|
|
||||||
/// This message
|
/// This message
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
@@ -161,6 +165,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
backgroundColor: StreamChatTheme.of(context).accentColor,
|
backgroundColor: StreamChatTheme.of(context).accentColor,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.done,
|
Icons.done,
|
||||||
|
color: Colors.white,
|
||||||
size: 4,
|
size: 4,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -192,7 +197,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
),
|
),
|
||||||
child: CircleAvatar(
|
child: CircleAvatar(
|
||||||
radius: 4,
|
radius: 4,
|
||||||
backgroundColor: Color(0xffd0021B).withAlpha(125),
|
backgroundColor: Color(0xffd0021B).withOpacity(.1),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.error_outline,
|
Icons.error_outline,
|
||||||
size: 4,
|
size: 4,
|
||||||
@@ -234,7 +239,9 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
'This message was deleted...',
|
'This message was deleted...',
|
||||||
style: _messageTheme.messageText.copyWith(
|
style: _messageTheme.messageText.copyWith(
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
color: Colors.black,
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -252,7 +259,9 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.subdirectory_arrow_left,
|
Icons.subdirectory_arrow_left,
|
||||||
color: Colors.black12,
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white12
|
||||||
|
: Colors.black12,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -422,9 +431,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
int nOfAttachmentWidgets,
|
int nOfAttachmentWidgets,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) {
|
) {
|
||||||
final boxDecoration = _buildBoxDecoration(_isLastUser).copyWith(
|
final boxDecoration = _buildBoxDecoration(_isLastUser);
|
||||||
color: Color(0xffebebeb),
|
|
||||||
);
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 2.0),
|
padding: const EdgeInsets.only(bottom: 2.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -435,7 +442,8 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
child: Container(
|
child: Container(
|
||||||
decoration: boxDecoration,
|
decoration: boxDecoration,
|
||||||
constraints: BoxConstraints.loose(
|
constraints: BoxConstraints.loose(
|
||||||
Size.fromWidth(MediaQuery.of(context).size.width * 0.7)),
|
Size.fromWidth(MediaQuery.of(context).size.width * 0.7),
|
||||||
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Column(
|
Column(
|
||||||
@@ -513,6 +521,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
_buildBoxDecoration(_isLastUser || nOfAttachmentWidgets > 0),
|
_buildBoxDecoration(_isLastUser || nOfAttachmentWidgets > 0),
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(10),
|
||||||
constraints: BoxConstraints.loose(
|
constraints: BoxConstraints.loose(
|
||||||
|
<<<<<<< HEAD
|
||||||
Size.fromWidth(MediaQuery.of(context).size.width * 0.7),
|
Size.fromWidth(MediaQuery.of(context).size.width * 0.7),
|
||||||
),
|
),
|
||||||
child: _buildSendingError(
|
child: _buildSendingError(
|
||||||
@@ -527,6 +536,38 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
|
|
||||||
if (widget.onMentionTap != null) {
|
if (widget.onMentionTap != null) {
|
||||||
widget.onMentionTap(mentionedUser);
|
widget.onMentionTap(mentionedUser);
|
||||||
|
=======
|
||||||
|
Size.fromWidth(MediaQuery.of(context).size.width * 0.7)),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
if (widget.message.status == MessageSendingStatus.FAILED)
|
||||||
|
Text(
|
||||||
|
'MESSAGE FAILED · CLICK TO TRY AGAIN',
|
||||||
|
style: _messageTheme.messageText.copyWith(
|
||||||
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white.withOpacity(.5)
|
||||||
|
: Colors.black.withOpacity(.5),
|
||||||
|
fontSize: 11,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
MarkdownBody(
|
||||||
|
data: text,
|
||||||
|
onTapLink: (link) {
|
||||||
|
if (link.startsWith('@')) {
|
||||||
|
final mentionedUser =
|
||||||
|
widget.message.mentionedUsers.firstWhere(
|
||||||
|
(u) => '@${u.name.replaceAll(' ', '')}' == link,
|
||||||
|
orElse: () => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (widget.onMentionTap != null) {
|
||||||
|
widget.onMentionTap(mentionedUser);
|
||||||
|
} else {
|
||||||
|
print('tap on ${mentionedUser.name}');
|
||||||
|
}
|
||||||
|
>>>>>>> master
|
||||||
} else {
|
} else {
|
||||||
print('tap on ${mentionedUser.name}');
|
print('tap on ${mentionedUser.name}');
|
||||||
}
|
}
|
||||||
@@ -662,7 +703,6 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
color: Color(0xffebebeb),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -674,7 +714,11 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
right: !_isMyMessage ? 8 : null,
|
right: !_isMyMessage ? 8 : null,
|
||||||
top: -6,
|
top: -6,
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
painter: _ReactionBubblePainter(),
|
painter: _ReactionBubblePainter(
|
||||||
|
Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: SizedBox();
|
: SizedBox();
|
||||||
@@ -823,12 +867,18 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
fillColor: Colors.black.withOpacity(.1),
|
fillColor:
|
||||||
|
Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white.withOpacity(.1)
|
||||||
|
: Colors.black.withOpacity(.1),
|
||||||
padding: EdgeInsets.all(4),
|
padding: EdgeInsets.all(4),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.close,
|
Icons.close,
|
||||||
size: 15,
|
size: 15,
|
||||||
color: Colors.black,
|
color:
|
||||||
|
Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -881,7 +931,9 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
? const EdgeInsets.all(8)
|
? const EdgeInsets.all(8)
|
||||||
: EdgeInsets.zero,
|
: EdgeInsets.zero,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black,
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(14))),
|
borderRadius: BorderRadius.all(Radius.circular(14))),
|
||||||
child: AnimatedSwitcher(
|
child: AnimatedSwitcher(
|
||||||
duration: Duration(milliseconds: 300),
|
duration: Duration(milliseconds: 300),
|
||||||
@@ -912,7 +964,11 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
widget.message.reactionCounts.values
|
widget.message.reactionCounts.values
|
||||||
.fold(0, (t, v) => v + t)
|
.fold(0, (t, v) => v + t)
|
||||||
.toString(),
|
.toString(),
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.black
|
||||||
|
: Colors.white,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -931,6 +987,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
Widget _buildImage(
|
Widget _buildImage(
|
||||||
Attachment attachment,
|
Attachment attachment,
|
||||||
) {
|
) {
|
||||||
|
<<<<<<< HEAD
|
||||||
return Hero(
|
return Hero(
|
||||||
tag: attachment.imageUrl ?? attachment.assetUrl ?? attachment.thumbUrl,
|
tag: attachment.imageUrl ?? attachment.assetUrl ?? attachment.thumbUrl,
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
@@ -958,6 +1015,17 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl,
|
attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl,
|
||||||
errorWidget: (context, url, error) => _buildErrorImage(attachment),
|
errorWidget: (context, url, error) => _buildErrorImage(attachment),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
|
=======
|
||||||
|
final errorWidget = Container(
|
||||||
|
width: 200,
|
||||||
|
height: 140,
|
||||||
|
color: Color(0xffd0021B).withOpacity(.1),
|
||||||
|
child: Center(
|
||||||
|
child: Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
>>>>>>> master
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1059,29 +1127,49 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
Widget _buildTimestamp(Alignment alignment) {
|
Widget _buildTimestamp(Alignment alignment) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(top: 5.0),
|
padding: const EdgeInsets.only(top: 5.0),
|
||||||
child: widget.message.createdAt != null
|
child: RichText(
|
||||||
? Text(
|
text: TextSpan(
|
||||||
Jiffy(widget.message.createdAt.toLocal()).format('HH:mm'),
|
style: _messageTheme.createdAt,
|
||||||
style: _messageTheme.createdAt,
|
children: <TextSpan>[
|
||||||
)
|
if (!_isMyMessage && widget.showOtherMessageUsername)
|
||||||
: SizedBox(),
|
TextSpan(
|
||||||
|
text: widget.message.user.name,
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
if (widget.message.createdAt != null)
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
Jiffy(widget.message.createdAt.toLocal()).format(' HH:mm'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxDecoration _buildBoxDecoration(bool rectBorders) {
|
BoxDecoration _buildBoxDecoration(bool rectBorders) {
|
||||||
return BoxDecoration(
|
return BoxDecoration(
|
||||||
border:
|
border: _isMyMessage
|
||||||
_isMyMessage ? null : Border.all(color: Colors.black.withAlpha(8)),
|
? null
|
||||||
|
: Border.all(
|
||||||
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white.withAlpha(24)
|
||||||
|
: Colors.black.withAlpha(24)),
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular((_isMyMessage || !rectBorders) ? 16 : 2),
|
topLeft: Radius.circular((_isMyMessage || !rectBorders) ? 16 : 2),
|
||||||
bottomLeft: Radius.circular(_isMyMessage ? 16 : 2),
|
bottomLeft: Radius.circular(_isMyMessage ? 16 : 2),
|
||||||
topRight: Radius.circular((_isMyMessage && rectBorders) ? 2 : 16),
|
topRight: Radius.circular((_isMyMessage && rectBorders) ? 2 : 16),
|
||||||
bottomRight: Radius.circular(_isMyMessage ? 2 : 16),
|
bottomRight: Radius.circular(_isMyMessage ? 2 : 16),
|
||||||
),
|
),
|
||||||
|
<<<<<<< HEAD
|
||||||
color: (widget.message.status == MessageSendingStatus.FAILED ||
|
color: (widget.message.status == MessageSendingStatus.FAILED ||
|
||||||
widget.message.status == MessageSendingStatus.FAILED_UPDATE ||
|
widget.message.status == MessageSendingStatus.FAILED_UPDATE ||
|
||||||
widget.message.status == MessageSendingStatus.FAILED_DELETE)
|
widget.message.status == MessageSendingStatus.FAILED_DELETE)
|
||||||
? Color(0xffd0021B).withAlpha(26)
|
? Color(0xffd0021B).withAlpha(26)
|
||||||
|
=======
|
||||||
|
color: widget.message.status == MessageSendingStatus.FAILED
|
||||||
|
? Color(0xffd0021B).withOpacity(.1)
|
||||||
|
>>>>>>> master
|
||||||
: _messageTheme.messageBackgroundColor,
|
: _messageTheme.messageBackgroundColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1093,9 +1181,13 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ReactionBubblePainter extends CustomPainter {
|
class _ReactionBubblePainter extends CustomPainter {
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
_ReactionBubblePainter(this.color);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final paint = Paint()..color = Colors.black;
|
final paint = Paint()..color = color;
|
||||||
final path = Path();
|
final path = Path();
|
||||||
path.arcToPoint(Offset(-6, -6));
|
path.arcToPoint(Offset(-6, -6));
|
||||||
path.arcToPoint(Offset(0, 10));
|
path.arcToPoint(Offset(0, 10));
|
||||||
|
|||||||
+30
-26
@@ -68,33 +68,37 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
|||||||
return StreamChatTheme(
|
return StreamChatTheme(
|
||||||
data: theme,
|
data: theme,
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) => Theme(
|
builder: (context) {
|
||||||
data: Theme.of(context).copyWith(
|
final materialTheme = Theme.of(context);
|
||||||
accentColor: StreamChatTheme.of(context).accentColor,
|
final isDark = materialTheme.brightness == Brightness.dark;
|
||||||
scaffoldBackgroundColor: Colors.white,
|
return Theme(
|
||||||
backgroundColor: Colors.white,
|
data: materialTheme.copyWith(
|
||||||
),
|
accentColor: StreamChatTheme.of(context).accentColor,
|
||||||
child: WillPopScope(
|
scaffoldBackgroundColor: isDark ? Colors.black : Colors.white,
|
||||||
onWillPop: () async {
|
backgroundColor: isDark ? Colors.black : Colors.white,
|
||||||
if (_navigatorKey.currentState.canPop()) {
|
|
||||||
_navigatorKey.currentState.pop();
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Navigator(
|
|
||||||
initialRoute: '/',
|
|
||||||
key: _navigatorKey,
|
|
||||||
onGenerateRoute: (settings) {
|
|
||||||
return MaterialPageRoute(
|
|
||||||
settings: settings,
|
|
||||||
builder: (_) => widget.child,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
child: WillPopScope(
|
||||||
),
|
onWillPop: () async {
|
||||||
|
if (_navigatorKey.currentState.canPop()) {
|
||||||
|
_navigatorKey.currentState.pop();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Navigator(
|
||||||
|
initialRoute: '/',
|
||||||
|
key: _navigatorKey,
|
||||||
|
onGenerateRoute: (settings) {
|
||||||
|
return MaterialPageRoute(
|
||||||
|
settings: settings,
|
||||||
|
builder: (_) => widget.child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,9 +166,10 @@ class StreamChatThemeData {
|
|||||||
/// Get the default Stream Chat theme
|
/// Get the default Stream Chat theme
|
||||||
static StreamChatThemeData getDefaultTheme(ThemeData theme) {
|
static StreamChatThemeData getDefaultTheme(ThemeData theme) {
|
||||||
final accentColor = Color(0xff006cff);
|
final accentColor = Color(0xff006cff);
|
||||||
|
final isDark = theme.brightness == Brightness.dark;
|
||||||
return StreamChatThemeData(
|
return StreamChatThemeData(
|
||||||
accentColor: accentColor,
|
accentColor: accentColor,
|
||||||
primaryColor: Colors.white,
|
primaryColor: isDark ? Colors.black : Colors.white,
|
||||||
channelPreviewTheme: ChannelPreviewTheme(
|
channelPreviewTheme: ChannelPreviewTheme(
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarTheme(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
@@ -179,15 +180,17 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
title: TextStyle(
|
title: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Colors.black,
|
color: isDark ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
subtitle: TextStyle(
|
subtitle: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: Colors.black,
|
color: isDark ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
lastMessageAt: TextStyle(
|
lastMessageAt: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Colors.black.withOpacity(.5),
|
color: isDark
|
||||||
|
? Colors.white.withOpacity(.5)
|
||||||
|
: Colors.black.withOpacity(.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
channelTheme: ChannelTheme(
|
channelTheme: ChannelTheme(
|
||||||
@@ -202,17 +205,20 @@ class StreamChatThemeData {
|
|||||||
width: 40,
|
width: 40,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
color: Colors.white,
|
color: isDark ? Colors.black : Colors.white,
|
||||||
title: TextStyle(
|
title: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Colors.black,
|
color: isDark ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
lastMessageAt: TextStyle(
|
lastMessageAt: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Colors.black.withOpacity(.5),
|
color: isDark
|
||||||
|
? Colors.white.withOpacity(.5)
|
||||||
|
: Colors.black.withOpacity(.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
inputBackground: Colors.black.withAlpha(12),
|
inputBackground:
|
||||||
|
isDark ? Colors.black.withAlpha(12) : Colors.white.withAlpha(12),
|
||||||
inputGradient: LinearGradient(colors: [
|
inputGradient: LinearGradient(colors: [
|
||||||
Color(0xFF00AEFF),
|
Color(0xFF00AEFF),
|
||||||
Color(0xFF0076FF),
|
Color(0xFF0076FF),
|
||||||
@@ -221,10 +227,12 @@ class StreamChatThemeData {
|
|||||||
ownMessageTheme: MessageTheme(
|
ownMessageTheme: MessageTheme(
|
||||||
messageText: TextStyle(
|
messageText: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
color: Colors.black,
|
color: isDark ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
createdAt: TextStyle(
|
createdAt: TextStyle(
|
||||||
color: Colors.black.withOpacity(.5),
|
color: isDark
|
||||||
|
? Colors.white.withOpacity(.5)
|
||||||
|
: Colors.black.withOpacity(.5),
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
replies: TextStyle(
|
replies: TextStyle(
|
||||||
@@ -232,7 +240,7 @@ class StreamChatThemeData {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
messageBackgroundColor: Color(0xffebebeb),
|
messageBackgroundColor: Color(0x33ebebeb),
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarTheme(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
@@ -244,10 +252,12 @@ class StreamChatThemeData {
|
|||||||
otherMessageTheme: MessageTheme(
|
otherMessageTheme: MessageTheme(
|
||||||
messageText: TextStyle(
|
messageText: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
color: Colors.black,
|
color: isDark ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
createdAt: TextStyle(
|
createdAt: TextStyle(
|
||||||
color: Colors.black.withOpacity(.5),
|
color: isDark
|
||||||
|
? Colors.white.withOpacity(.5)
|
||||||
|
: Colors.black.withOpacity(.5),
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
replies: TextStyle(
|
replies: TextStyle(
|
||||||
@@ -255,7 +265,7 @@ class StreamChatThemeData {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
messageBackgroundColor: Colors.white,
|
messageBackgroundColor: isDark ? Colors.black : Colors.white,
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarTheme(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
|
|||||||
@@ -122,12 +122,16 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fillColor: Colors.black.withOpacity(.1),
|
fillColor: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white.withOpacity(.1)
|
||||||
|
: Colors.black.withOpacity(.1),
|
||||||
padding: EdgeInsets.all(4),
|
padding: EdgeInsets.all(4),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.close,
|
Icons.close,
|
||||||
size: 15,
|
size: 15,
|
||||||
color: Colors.black,
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
name: stream_chat_flutter
|
name: stream_chat_flutter
|
||||||
homepage: https://github.com/GetStream/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.
|
description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter.
|
||||||
version: 0.1.14
|
version: 0.1.17
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.3.0 <3.0.0"
|
sdk: ">=2.3.0 <3.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user