Merge branch 'master' into feature/notifications
This commit is contained in:
@@ -1,3 +1,21 @@
|
|||||||
|
## 0.1.19
|
||||||
|
|
||||||
|
- Fix video aspect ratio
|
||||||
|
|
||||||
|
- Add property to decide whether to enable video fullscreen
|
||||||
|
|
||||||
|
- Add property to hide the attachment button
|
||||||
|
|
||||||
|
- Do not show send button if an attachment is still uploading
|
||||||
|
|
||||||
|
- Unfocus and disable the TextField before opening the camera (workaround for flutter/flutter#42417)
|
||||||
|
|
||||||
|
- Add gesture (vertical drag down) to close the keyboard
|
||||||
|
|
||||||
|
- Add keyboard type parameters (set it to TextInputType.text to show the submit button that will even close the keyboard)
|
||||||
|
|
||||||
|
The property showVideoFullScreen was added mainly because of this issue brianegan/chewie#261
|
||||||
|
|
||||||
## 0.1.18
|
## 0.1.18
|
||||||
|
|
||||||
- Add message list date separators
|
- Add message list date separators
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||

|

|
||||||

|

|
||||||
[](https://codecov.io/gh/GetStream/stream-chat-flutter)
|
[](https://codecov.io/gh/GetStream/stream-chat-flutter)
|
||||||
|
[](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|
|
||||||
**Quick Links**
|
**Quick Links**
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ The example is available under the [example](https://github.com/GetStream/stream
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
dependencies:
|
dependencies:
|
||||||
stream_chat_flutter: ^0.1.15
|
stream_chat_flutter: ^0.1.19
|
||||||
```
|
```
|
||||||
|
|
||||||
You should then run `flutter packages get`
|
You should then run `flutter packages get`
|
||||||
|
|||||||
+47
-17
@@ -63,6 +63,8 @@ class MessageInput extends StatefulWidget {
|
|||||||
this.parentMessage,
|
this.parentMessage,
|
||||||
this.editMessage,
|
this.editMessage,
|
||||||
this.maxHeight = 150,
|
this.maxHeight = 150,
|
||||||
|
this.keyboardType = TextInputType.multiline,
|
||||||
|
this.disableAttachments = false,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// Message to edit
|
/// Message to edit
|
||||||
@@ -77,6 +79,12 @@ class MessageInput extends StatefulWidget {
|
|||||||
/// Maximum Height for the TextField to grow before it starts scrolling
|
/// Maximum Height for the TextField to grow before it starts scrolling
|
||||||
final double maxHeight;
|
final double maxHeight;
|
||||||
|
|
||||||
|
/// The keyboard type assigned to the TextField
|
||||||
|
final TextInputType keyboardType;
|
||||||
|
|
||||||
|
/// If true the attachments button will not be displayed
|
||||||
|
final bool disableAttachments;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageInputState createState() => _MessageInputState();
|
_MessageInputState createState() => _MessageInputState();
|
||||||
}
|
}
|
||||||
@@ -87,6 +95,7 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
final List<User> _mentionedUsers = [];
|
final List<User> _mentionedUsers = [];
|
||||||
|
|
||||||
TextEditingController _textController;
|
TextEditingController _textController;
|
||||||
|
bool _inputEnabled = true;
|
||||||
bool _messageIsPresent = false;
|
bool _messageIsPresent = false;
|
||||||
bool _typingStarted = false;
|
bool _typingStarted = false;
|
||||||
OverlayEntry _commandsOverlay, _mentionsOverlay;
|
OverlayEntry _commandsOverlay, _mentionsOverlay;
|
||||||
@@ -94,20 +103,27 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
child: Padding(
|
child: GestureDetector(
|
||||||
padding: const EdgeInsets.all(8.0),
|
onPanUpdate: (details) {
|
||||||
child: Stack(
|
if (details.delta.dy > 0) {
|
||||||
overflow: Overflow.visible,
|
_focusNode.unfocus();
|
||||||
children: <Widget>[
|
}
|
||||||
_buildBorder(context),
|
},
|
||||||
Column(
|
child: Padding(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
padding: const EdgeInsets.all(8.0),
|
||||||
children: [
|
child: Stack(
|
||||||
_buildAttachments(),
|
overflow: Overflow.visible,
|
||||||
_buildTextField(context),
|
children: <Widget>[
|
||||||
],
|
_buildBorder(context),
|
||||||
),
|
Column(
|
||||||
],
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildAttachments(),
|
||||||
|
_buildTextField(context),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -118,7 +134,7 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
direction: Axis.horizontal,
|
direction: Axis.horizontal,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
_buildAttachmentButton(),
|
if (!widget.disableAttachments) _buildAttachmentButton(),
|
||||||
_buildTextInput(context),
|
_buildTextInput(context),
|
||||||
_animateSendButton(context),
|
_animateSendButton(context),
|
||||||
],
|
],
|
||||||
@@ -127,7 +143,8 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
|
|
||||||
AnimatedCrossFade _animateSendButton(BuildContext context) {
|
AnimatedCrossFade _animateSendButton(BuildContext context) {
|
||||||
return AnimatedCrossFade(
|
return AnimatedCrossFade(
|
||||||
crossFadeState: (_messageIsPresent || _attachments.isNotEmpty)
|
crossFadeState: ((_messageIsPresent || _attachments.isNotEmpty) &&
|
||||||
|
_attachments.every((a) => a.uploaded == true))
|
||||||
? CrossFadeState.showFirst
|
? CrossFadeState.showFirst
|
||||||
: CrossFadeState.showSecond,
|
: CrossFadeState.showSecond,
|
||||||
firstChild: _buildSendButton(context),
|
firstChild: _buildSendButton(context),
|
||||||
@@ -143,11 +160,13 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
maxHeight: widget.maxHeight,
|
maxHeight: widget.maxHeight,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
key: Key('messageInputText'),
|
key: Key('messageInputText'),
|
||||||
|
enabled: _inputEnabled,
|
||||||
minLines: null,
|
minLines: null,
|
||||||
maxLines: null,
|
maxLines: null,
|
||||||
onSubmitted: (_) {
|
onSubmitted: (_) {
|
||||||
_sendMessage(context);
|
_sendMessage(context);
|
||||||
},
|
},
|
||||||
|
keyboardType: widget.keyboardType,
|
||||||
controller: _textController,
|
controller: _textController,
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
onChanged: (s) {
|
onChanged: (s) {
|
||||||
@@ -507,6 +526,10 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _showAttachmentModal() {
|
void _showAttachmentModal() {
|
||||||
|
if (_focusNode.hasFocus) {
|
||||||
|
_focusNode.unfocus();
|
||||||
|
}
|
||||||
|
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
@@ -549,7 +572,6 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
leading: Icon(Icons.camera_alt),
|
leading: Icon(Icons.camera_alt),
|
||||||
title: Text('Photo from camera'),
|
title: Text('Photo from camera'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ImagePicker.pickImage(source: ImageSource.camera);
|
|
||||||
_pickFile(FileType.image, true);
|
_pickFile(FileType.image, true);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
@@ -576,6 +598,10 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _pickFile(FileType type, bool camera) async {
|
void _pickFile(FileType type, bool camera) async {
|
||||||
|
setState(() {
|
||||||
|
_inputEnabled = false;
|
||||||
|
});
|
||||||
|
|
||||||
File file;
|
File file;
|
||||||
|
|
||||||
if (camera) {
|
if (camera) {
|
||||||
@@ -588,6 +614,10 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
file = await FilePicker.getFile(type: type);
|
file = await FilePicker.getFile(type: type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_inputEnabled = true;
|
||||||
|
});
|
||||||
|
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-37
@@ -43,6 +43,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
this.isParent = false,
|
this.isParent = false,
|
||||||
this.onMentionTap,
|
this.onMentionTap,
|
||||||
this.showOtherMessageUsername = false,
|
this.showOtherMessageUsername = false,
|
||||||
|
this.showVideoFullScreen = true,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// Function called on mention tap
|
/// Function called on mention tap
|
||||||
@@ -69,6 +70,9 @@ class MessageWidget extends StatefulWidget {
|
|||||||
/// True if this is the parent of the thread being showed
|
/// True if this is the parent of the thread being showed
|
||||||
final bool isParent;
|
final bool isParent;
|
||||||
|
|
||||||
|
/// True if the video player will allow fullscreen mode
|
||||||
|
final bool showVideoFullScreen;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageWidgetState createState() => _MessageWidgetState();
|
_MessageWidgetState createState() => _MessageWidgetState();
|
||||||
}
|
}
|
||||||
@@ -1030,45 +1034,53 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
_videoControllers[attachment.assetUrl] = videoController;
|
_videoControllers[attachment.assetUrl] = videoController;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChewieController chewieController;
|
return FutureBuilder<void>(
|
||||||
if (_chuwieControllers.containsKey(attachment.assetUrl)) {
|
future: videoController.initialize(),
|
||||||
chewieController = _chuwieControllers[attachment.assetUrl];
|
builder: (_, snapshot) {
|
||||||
} else {
|
if (snapshot.connectionState != ConnectionState.done) {
|
||||||
chewieController = ChewieController(
|
return Center(
|
||||||
videoPlayerController: videoController,
|
child: CircularProgressIndicator(),
|
||||||
autoInitialize: true,
|
);
|
||||||
errorBuilder: (_, e) {
|
}
|
||||||
if (attachment.thumbUrl == null) {
|
ChewieController chewieController;
|
||||||
return _buildErrorImage(attachment);
|
if (_chuwieControllers.containsKey(attachment.assetUrl)) {
|
||||||
}
|
chewieController = _chuwieControllers[attachment.assetUrl];
|
||||||
return Stack(
|
} else {
|
||||||
children: <Widget>[
|
chewieController = ChewieController(
|
||||||
Container(
|
allowFullScreen: widget.showVideoFullScreen,
|
||||||
decoration: BoxDecoration(
|
videoPlayerController: videoController,
|
||||||
image: DecorationImage(
|
autoInitialize: false,
|
||||||
fit: BoxFit.cover,
|
aspectRatio: videoController.value.aspectRatio,
|
||||||
image: CachedNetworkImageProvider(
|
errorBuilder: (_, e) {
|
||||||
attachment.thumbUrl,
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
image: CachedNetworkImageProvider(
|
||||||
|
attachment.thumbUrl,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Material(
|
||||||
),
|
color: Colors.transparent,
|
||||||
Material(
|
child: InkWell(
|
||||||
color: Colors.transparent,
|
onTap: () => _launchURL(attachment.titleLink),
|
||||||
child: InkWell(
|
),
|
||||||
onTap: () => _launchURL(attachment.titleLink),
|
),
|
||||||
),
|
],
|
||||||
),
|
);
|
||||||
],
|
});
|
||||||
);
|
_chuwieControllers[attachment.assetUrl] = chewieController;
|
||||||
});
|
}
|
||||||
_chuwieControllers[attachment.assetUrl] = chewieController;
|
return Chewie(
|
||||||
}
|
key: ValueKey<String>(
|
||||||
|
'ATTACHMENT-${attachment.title}-${widget.message.id}'),
|
||||||
return Chewie(
|
controller: chewieController,
|
||||||
key: ValueKey<String>(
|
);
|
||||||
'ATTACHMENT-${attachment.title}-${widget.message.id}'),
|
},
|
||||||
controller: chewieController,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+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.18
|
version: 0.1.19
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.3.0 <3.0.0"
|
sdk: ">=2.3.0 <3.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user