Merge branch 'develop' into dependabot/pub/packages/stream_chat_flutter/share_plus-8.0.0
This commit is contained in:
@@ -16,7 +16,7 @@ jobs:
|
|||||||
conventional_pr_title:
|
conventional_pr_title:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: amannn/action-semantic-pull-request@v5.3.0
|
- uses: amannn/action-semantic-pull-request@v5.4.0
|
||||||
with:
|
with:
|
||||||
scopes: |
|
scopes: |
|
||||||
llc
|
llc
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ name: stream_flutter_workflow
|
|||||||
env:
|
env:
|
||||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
|
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
|
||||||
flutter_channel: "stable"
|
flutter_channel: "stable"
|
||||||
|
flutter_version: "3.10.6"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -36,6 +37,7 @@ jobs:
|
|||||||
- name: "Install Flutter"
|
- name: "Install Flutter"
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
|
flutter-version: ${{ env.flutter_version }}
|
||||||
cache: true
|
cache: true
|
||||||
channel: ${{ env.flutter_channel }}
|
channel: ${{ env.flutter_channel }}
|
||||||
- name: "Install Tools"
|
- name: "Install Tools"
|
||||||
@@ -63,6 +65,7 @@ jobs:
|
|||||||
- name: "Install Flutter"
|
- name: "Install Flutter"
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
|
flutter-version: ${{ env.flutter_version }}
|
||||||
cache: true
|
cache: true
|
||||||
channel: ${{ env.flutter_channel }}
|
channel: ${{ env.flutter_channel }}
|
||||||
- name: "Install Tools"
|
- name: "Install Tools"
|
||||||
@@ -88,6 +91,7 @@ jobs:
|
|||||||
- name: "Install Flutter"
|
- name: "Install Flutter"
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
|
flutter-version: ${{ env.flutter_version }}
|
||||||
cache: true
|
cache: true
|
||||||
channel: ${{ env.flutter_channel }}
|
channel: ${{ env.flutter_channel }}
|
||||||
- name: "Install Tools"
|
- name: "Install Tools"
|
||||||
@@ -106,27 +110,27 @@ jobs:
|
|||||||
token: ${{secrets.CODECOV_TOKEN}}
|
token: ${{secrets.CODECOV_TOKEN}}
|
||||||
files: packages/*/coverage/lcov.info
|
files: packages/*/coverage/lcov.info
|
||||||
- name: "Stream Chat Coverage Check"
|
- name: "Stream Chat Coverage Check"
|
||||||
uses: VeryGoodOpenSource/very_good_coverage@v2.1.0
|
uses: VeryGoodOpenSource/very_good_coverage@v2.2.0
|
||||||
with:
|
with:
|
||||||
path: packages/stream_chat/coverage/lcov.info
|
path: packages/stream_chat/coverage/lcov.info
|
||||||
min_coverage: 79
|
min_coverage: 79
|
||||||
- name: "Stream Chat Localizations Coverage Check"
|
- name: "Stream Chat Localizations Coverage Check"
|
||||||
uses: VeryGoodOpenSource/very_good_coverage@v2.1.0
|
uses: VeryGoodOpenSource/very_good_coverage@v2.2.0
|
||||||
with:
|
with:
|
||||||
path: packages/stream_chat_localizations/coverage/lcov.info
|
path: packages/stream_chat_localizations/coverage/lcov.info
|
||||||
min_coverage: 100
|
min_coverage: 100
|
||||||
- name: "Stream Chat Persistence Coverage Check"
|
- name: "Stream Chat Persistence Coverage Check"
|
||||||
uses: VeryGoodOpenSource/very_good_coverage@v2.1.0
|
uses: VeryGoodOpenSource/very_good_coverage@v2.2.0
|
||||||
with:
|
with:
|
||||||
path: packages/stream_chat_persistence/coverage/lcov.info
|
path: packages/stream_chat_persistence/coverage/lcov.info
|
||||||
min_coverage: 95
|
min_coverage: 95
|
||||||
- name: "Stream Chat Flutter Core Coverage Check"
|
- name: "Stream Chat Flutter Core Coverage Check"
|
||||||
uses: VeryGoodOpenSource/very_good_coverage@v2.1.0
|
uses: VeryGoodOpenSource/very_good_coverage@v2.2.0
|
||||||
with:
|
with:
|
||||||
path: packages/stream_chat_flutter_core/coverage/lcov.info
|
path: packages/stream_chat_flutter_core/coverage/lcov.info
|
||||||
min_coverage: 30
|
min_coverage: 30
|
||||||
- name: "Stream Chat Flutter Coverage Check"
|
- name: "Stream Chat Flutter Coverage Check"
|
||||||
uses: VeryGoodOpenSource/very_good_coverage@v2.1.0
|
uses: VeryGoodOpenSource/very_good_coverage@v2.2.0
|
||||||
with:
|
with:
|
||||||
path: packages/stream_chat_flutter/coverage/lcov.info
|
path: packages/stream_chat_flutter/coverage/lcov.info
|
||||||
min_coverage: 44
|
min_coverage: 44
|
||||||
|
|||||||
+3
-2
@@ -21,8 +21,9 @@ provided inside the `messageBuilder` parameter of the `StreamMessageListView` li
|
|||||||
```dart
|
```dart
|
||||||
StreamMessageListView(
|
StreamMessageListView(
|
||||||
messageBuilder: (context, details, messageList, defaultImpl) {
|
messageBuilder: (context, details, messageList, defaultImpl) {
|
||||||
// Your implementation of the message here
|
return defaultImpl.copyWith(
|
||||||
// E.g: return Text(details.message.text ?? '');
|
...
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
```
|
```
|
||||||
|
|||||||
+20
-15
@@ -91,7 +91,7 @@ StreamMessageListView(
|
|||||||
messageBuilder: (context, messageDetails, messageList, defaultWidget) {
|
messageBuilder: (context, messageDetails, messageList, defaultWidget) {
|
||||||
return defaultWidget.copyWith(
|
return defaultWidget.copyWith(
|
||||||
textBuilder: (context, message) {
|
textBuilder: (context, message) {
|
||||||
return Text(message.text);
|
return Text(message.text ?? '');
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -108,14 +108,16 @@ StreamMessageListView(
|
|||||||
messageBuilder: (context, messageDetails, messageList, defaultWidget) {
|
messageBuilder: (context, messageDetails, messageList, defaultWidget) {
|
||||||
return defaultWidget.copyWith(
|
return defaultWidget.copyWith(
|
||||||
textBuilder: (context, message) {
|
textBuilder: (context, message) {
|
||||||
final text = _replaceHashtags(message.text).replaceAll('\n', '\\\n');
|
final text = _replaceHashtags(message.text)?.replaceAll('\n', '\\\n');
|
||||||
final messageTheme = StreamChatTheme.of(context).ownMessageTheme;
|
final messageTheme = StreamChatTheme.of(context).ownMessageTheme;
|
||||||
|
|
||||||
|
if (text == null) return const SizedBox();
|
||||||
|
|
||||||
return MarkdownBody(
|
return MarkdownBody(
|
||||||
data: text,
|
data: text,
|
||||||
onTapLink: (
|
onTapLink: (
|
||||||
String link,
|
String link,
|
||||||
String href,
|
String? href,
|
||||||
String title,
|
String title,
|
||||||
) {
|
) {
|
||||||
// Do something with tapped hashtag
|
// Do something with tapped hashtag
|
||||||
@@ -123,16 +125,16 @@ StreamMessageListView(
|
|||||||
styleSheet: MarkdownStyleSheet.fromTheme(
|
styleSheet: MarkdownStyleSheet.fromTheme(
|
||||||
Theme.of(context).copyWith(
|
Theme.of(context).copyWith(
|
||||||
textTheme: Theme.of(context).textTheme.apply(
|
textTheme: Theme.of(context).textTheme.apply(
|
||||||
bodyColor: messageTheme.messageText.color,
|
bodyColor: messageTheme.messageTextStyle?.color,
|
||||||
decoration: messageTheme.messageText.decoration,
|
decoration: messageTheme.messageTextStyle?.decoration,
|
||||||
decorationColor: messageTheme.messageText.decorationColor,
|
decorationColor: messageTheme.messageTextStyle?.decorationColor,
|
||||||
decorationStyle: messageTheme.messageText.decorationStyle,
|
decorationStyle: messageTheme.messageTextStyle?.decorationStyle,
|
||||||
fontFamily: messageTheme.messageText.fontFamily,
|
fontFamily: messageTheme.messageTextStyle?.fontFamily,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).copyWith(
|
).copyWith(
|
||||||
a: messageTheme.messageLinks,
|
a: messageTheme.messageLinksStyle,
|
||||||
p: messageTheme.messageText,
|
p: messageTheme.messageTextStyle,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -140,13 +142,16 @@ StreamMessageListView(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
String _replaceHashtags(String text) {
|
String? _replaceHashtags(String? text) {
|
||||||
RegExp exp = new RegExp(r"\B#\w\w+");
|
if (text == null) return null;
|
||||||
|
|
||||||
|
final exp = RegExp(r"\B#\w\w+");
|
||||||
|
String result = text;
|
||||||
exp.allMatches(text).forEach((match){
|
exp.allMatches(text).forEach((match){
|
||||||
text = text.replaceAll(
|
text = text!.replaceAll(
|
||||||
'${match.group(0)}', '[${match.group(0)}](${match.group(0).replaceAll(' ', '')})');
|
'${match.group(0)}', '[${match.group(0)}](${match.group(0)?.replaceAll(' ', '')})');
|
||||||
});
|
});
|
||||||
return text;
|
return result;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -68,8 +68,8 @@ StreamMessageListView(
|
|||||||
return defaultMessage.copyWith(
|
return defaultMessage.copyWith(
|
||||||
customActions: [
|
customActions: [
|
||||||
StreamMessageAction(
|
StreamMessageAction(
|
||||||
leading: Icon(Icons.add),
|
leading: const Icon(Icons.add),
|
||||||
title: Text('Demo Action'),
|
title: const Text('Demo Action'),
|
||||||
onTap: (message) {
|
onTap: (message) {
|
||||||
/// Complete action here
|
/// Complete action here
|
||||||
},
|
},
|
||||||
|
|||||||
+31
-28
@@ -35,9 +35,9 @@ Message(
|
|||||||
text: 'This is my location',
|
text: 'This is my location',
|
||||||
attachments: [
|
attachments: [
|
||||||
Attachment(
|
Attachment(
|
||||||
uploadState: UploadState.success(),
|
uploadState: const UploadState.success(),
|
||||||
type: 'location',
|
type: 'location',
|
||||||
extraData: {
|
extraData: const {
|
||||||
'latitude': 'fetched_latitude',
|
'latitude': 'fetched_latitude',
|
||||||
'longitude': 'fetched_longitude',
|
'longitude': 'fetched_longitude',
|
||||||
},
|
},
|
||||||
@@ -62,14 +62,13 @@ First, we add a button which when clicked fetches and shares location into the `
|
|||||||
StreamMessageInput(
|
StreamMessageInput(
|
||||||
actions: [
|
actions: [
|
||||||
InkWell(
|
InkWell(
|
||||||
child: Icon(
|
child: const Icon(
|
||||||
Icons.location_on,
|
Icons.location_on,
|
||||||
size: 20.0,
|
size: 20,
|
||||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
color: StreamChatTheme.of(context).colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
var channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
var user = StreamChat.of(context).user;
|
|
||||||
|
|
||||||
_determinePosition().then((value) {
|
_determinePosition().then((value) {
|
||||||
channel.sendMessage(
|
channel.sendMessage(
|
||||||
@@ -77,7 +76,7 @@ StreamMessageInput(
|
|||||||
text: 'This is my location',
|
text: 'This is my location',
|
||||||
attachments: [
|
attachments: [
|
||||||
Attachment(
|
Attachment(
|
||||||
uploadState: UploadState.success(),
|
uploadState: const UploadState.success(),
|
||||||
type: 'location',
|
type: 'location',
|
||||||
extraData: {
|
extraData: {
|
||||||
'latitude': value.latitude.toString(),
|
'latitude': value.latitude.toString(),
|
||||||
@@ -126,8 +125,7 @@ Next, we build the Static Maps URL (Add your API key before using the code snipp
|
|||||||
|
|
||||||
```dart
|
```dart
|
||||||
String _buildMapAttachment(String lat, String long) {
|
String _buildMapAttachment(String lat, String long) {
|
||||||
var baseURL = 'https://maps.googleapis.com/maps/api/staticmap?';
|
final url = Uri(
|
||||||
var url = Uri(
|
|
||||||
scheme: 'https',
|
scheme: 'https',
|
||||||
host: 'maps.googleapis.com',
|
host: 'maps.googleapis.com',
|
||||||
port: 443,
|
port: 443,
|
||||||
@@ -155,8 +153,8 @@ StreamMessageListView(
|
|||||||
'location': (context, message, attachments) {
|
'location': (context, message, attachments) {
|
||||||
final attachmentWidget = Image.network(
|
final attachmentWidget = Image.network(
|
||||||
_buildMapAttachment(
|
_buildMapAttachment(
|
||||||
attachments[0].extraData['latitude'],
|
attachments[0].extraData['latitude'].toString(),
|
||||||
attachments[0].extraData['longitude'],
|
attachments[0].extraData['longitude'].toString(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -194,14 +192,14 @@ First, we add the attachment when the location button is clicked:
|
|||||||
InkWell(
|
InkWell(
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.location_on,
|
Icons.location_on,
|
||||||
size: 20.0,
|
size: 20,
|
||||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
color: StreamChatTheme.of(context).colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_determinePosition().then((value) {
|
_determinePosition().then((value) {
|
||||||
_messageInputController.addAttachment(
|
_messageInputController.addAttachment(
|
||||||
Attachment(
|
Attachment(
|
||||||
uploadState: UploadState.success(),
|
uploadState: const UploadState.success(),
|
||||||
type: 'location',
|
type: 'location',
|
||||||
extraData: {
|
extraData: {
|
||||||
'latitude': value.latitude.toString(),
|
'latitude': value.latitude.toString(),
|
||||||
@@ -227,14 +225,14 @@ StreamMessageInput(
|
|||||||
InkWell(
|
InkWell(
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.location_on,
|
Icons.location_on,
|
||||||
size: 20.0,
|
size: 20,
|
||||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
color: StreamChatTheme.of(context).colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_determinePosition().then((value) {
|
_determinePosition().then((value) {
|
||||||
_messageInputController.addAttachment(
|
_messageInputController.addAttachment(
|
||||||
Attachment(
|
Attachment(
|
||||||
uploadState: UploadState.success(),
|
uploadState: const UploadState.success(),
|
||||||
type: 'location',
|
type: 'location',
|
||||||
extraData: {
|
extraData: {
|
||||||
'latitude': value.latitude.toString(),
|
'latitude': value.latitude.toString(),
|
||||||
@@ -248,16 +246,21 @@ StreamMessageInput(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
attachmentThumbnailBuilders: {
|
mediaAttachmentBuilder: (
|
||||||
'location': (context, attachment) {
|
BuildContext context,
|
||||||
return Image.network(
|
Attachment attachment,
|
||||||
_buildMapAttachment(
|
ValueSetter<Attachment>? onRemovePressed,
|
||||||
attachment.extraData['latitude'],
|
) {
|
||||||
attachment.extraData['longitude'],
|
if (attachment.type == 'location') {
|
||||||
),
|
return Image.network(
|
||||||
);
|
_buildMapAttachment(
|
||||||
},
|
attachment.extraData['latitude'].toString(),
|
||||||
},
|
attachment.extraData['longitude'].toString(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return const SizedBox();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+10
-7
@@ -25,11 +25,14 @@ The initial attachments can be passed to the Attachment Picker Modal in two ways
|
|||||||
* By passing the `initialAttachments` parameter.
|
* By passing the `initialAttachments` parameter.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
|
StreamMessageInputController _messageInputController =
|
||||||
|
StreamMessageInputController();
|
||||||
|
...
|
||||||
showStreamAttachmentPickerModalBottomSheet(
|
showStreamAttachmentPickerModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
initialAttachments: [
|
initialAttachments: [
|
||||||
// Pass the initial attachments to the modal here if any are available already (optional)
|
// Pass the initial attachments to the modal here if any are available already (optional)
|
||||||
...messageInputController.attachments,
|
..._messageInputController.attachments,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
@@ -65,7 +68,7 @@ However, you can also customize the options by passing the `customOptions` param
|
|||||||
customOptions: [
|
customOptions: [
|
||||||
// Pass the custom attachment picker options here
|
// Pass the custom attachment picker options here
|
||||||
AttachmentPickerOption(
|
AttachmentPickerOption(
|
||||||
icon: Icon(Icons.audiotrack),
|
icon: const Icon(Icons.audiotrack),
|
||||||
supportedTypes: [AttachmentPickerType.audios],
|
supportedTypes: [AttachmentPickerType.audios],
|
||||||
optionViewBuilder: (context, attachmentPickerController) {
|
optionViewBuilder: (context, attachmentPickerController) {
|
||||||
return AudioPicker(
|
return AudioPicker(
|
||||||
@@ -87,7 +90,7 @@ The size of the attachment thumbnail item shown in the gallery picker can be def
|
|||||||
```dart
|
```dart
|
||||||
showStreamAttachmentPickerModalBottomSheet(
|
showStreamAttachmentPickerModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
attachmentThumbnailSize: ThumbnailSize.square(600),
|
attachmentThumbnailSize: const ThumbnailSize.square(600),
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -121,13 +124,13 @@ Possible values are between 0 and 100.
|
|||||||
|
|
||||||
The scale of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailScale` parameter.
|
The scale of the attachment thumbnail item shown in the gallery picker can be defined by passing the `attachmentThumbnailScale` parameter.
|
||||||
|
|
||||||
For example, if this is 2.0, it means that there are four image pixels for every one logical pixel, and the image's actual width and height are
|
For example, if this is 2, it means that there are four image pixels for every one logical pixel, and the image's actual width and height are
|
||||||
double the height and width that should be used when painting the image.
|
double the height and width that should be used when painting the image.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
showStreamAttachmentPickerModalBottomSheet(
|
showStreamAttachmentPickerModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
attachmentThumbnailScale: 2.0,
|
attachmentThumbnailScale: 2,
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -145,13 +148,13 @@ The `showStreamAttachmentPickerModalBottomSheet` function also accepts the param
|
|||||||
isDismissible: true,
|
isDismissible: true,
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
barrierColor: Colors.black.withOpacity(0.5),
|
barrierColor: Colors.black.withOpacity(0.5),
|
||||||
constraints: BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
maxHeight: 500,
|
maxHeight: 500,
|
||||||
maxWidth: 500,
|
maxWidth: 500,
|
||||||
),
|
),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.vertical(
|
borderRadius: BorderRadius.vertical(
|
||||||
top: Radius.circular(16.0),
|
top: Radius.circular(16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
+3
-3
@@ -63,19 +63,19 @@ class StreamEmojiAutocompleteOptions extends StatelessWidget {
|
|||||||
horizontalTitleGap: 0,
|
horizontalTitleGap: 0,
|
||||||
leading: Text(
|
leading: Text(
|
||||||
emoji.char,
|
emoji.char,
|
||||||
style: themeData.textTheme.headline6!.copyWith(
|
style: themeData.textTheme.titleLarge!.copyWith(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: SubstringHighlight(
|
title: SubstringHighlight(
|
||||||
text: emoji.shortName,
|
text: emoji.shortName,
|
||||||
term: query,
|
term: query,
|
||||||
textStyleHighlight: themeData.textTheme.headline6!.copyWith(
|
textStyleHighlight: themeData.textTheme.titleLarge!.copyWith(
|
||||||
color: Colors.yellow,
|
color: Colors.yellow,
|
||||||
fontSize: 14.5,
|
fontSize: 14.5,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
textStyle: themeData.textTheme.headline6!.copyWith(
|
textStyle: themeData.textTheme.titleLarge!.copyWith(
|
||||||
fontSize: 14.5,
|
fontSize: 14.5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+4
-3
@@ -25,8 +25,8 @@ If you're new to Stream Chat Flutter, we recommend looking at our [getting start
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
stream_chat_flutter: ^4.0.0
|
stream_chat_flutter: ^6.0.0
|
||||||
flutter_slidable: ^1.2.0
|
flutter_slidable: ^3.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
⚠️ Note: The examples shown in this guide use the above packages and versions.
|
⚠️ Note: The examples shown in this guide use the above packages and versions.
|
||||||
@@ -120,7 +120,8 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
onRefresh: _controller.refresh,
|
onRefresh: _controller.refresh,
|
||||||
child: StreamChannelListView(
|
child: StreamChannelListView(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
itemBuilder: (context, channel, tile) {
|
itemBuilder: (context, channels, index, tile) {
|
||||||
|
final channel = channels[index];
|
||||||
final chatTheme = StreamChatTheme.of(context);
|
final chatTheme = StreamChatTheme.of(context);
|
||||||
final backgroundColor = chatTheme.colorTheme.inputBg;
|
final backgroundColor = chatTheme.colorTheme.inputBg;
|
||||||
final canDeleteChannel = channel.ownCapabilities
|
final canDeleteChannel = channel.ownCapabilities
|
||||||
|
|||||||
@@ -29,41 +29,44 @@ factory StreamChatThemeData({
|
|||||||
Brightness? brightness,
|
Brightness? brightness,
|
||||||
TextTheme? textTheme,
|
TextTheme? textTheme,
|
||||||
ColorTheme? colorTheme,
|
ColorTheme? colorTheme,
|
||||||
ChannelListHeaderTheme? channelListHeaderTheme,
|
StreamChannelListHeaderThemeData? channelListHeaderTheme,
|
||||||
ChannelPreviewTheme? channelPreviewTheme,
|
StreamChannelPreviewThemeData? channelPreviewTheme,
|
||||||
ChannelTheme? channelTheme,
|
StreamChannelHeaderThemeData? channelHeaderTheme,
|
||||||
MessageTheme? otherMessageTheme,
|
StreamMessageThemeData? otherMessageTheme,
|
||||||
MessageTheme? ownMessageTheme,
|
StreamMessageThemeData? ownMessageTheme,
|
||||||
MessageInputTheme? messageInputTheme,
|
StreamMessageInputThemeData? messageInputTheme,
|
||||||
Widget Function(BuildContext, Channel)? defaultChannelImage,
|
|
||||||
Widget Function(BuildContext, User)? defaultUserImage,
|
Widget Function(BuildContext, User)? defaultUserImage,
|
||||||
|
PlaceholderUserImage? placeholderUserImage,
|
||||||
IconThemeData? primaryIconTheme,
|
IconThemeData? primaryIconTheme,
|
||||||
List<ReactionIcon>? reactionIcons,
|
List<StreamReactionIcon>? reactionIcons,
|
||||||
|
StreamGalleryHeaderThemeData? imageHeaderTheme,
|
||||||
|
StreamGalleryFooterThemeData? imageFooterTheme,
|
||||||
|
StreamMessageListViewThemeData? messageListViewTheme,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Stream Chat Theme in use
|
### Stream Chat Theme in use
|
||||||
|
|
||||||
Let's take a look at customizing widgets using `StreamChatTheme`. In the example below, we can change the default color theme to yellow and override the channel header's typography and colors.
|
Let's take a look at customizing widgets using `StreamChatThemeData`. In the example below, we can change the default color theme to yellow and override the channel header's typography and colors.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
builder: (context, child) => StreamChat(
|
MaterialApp(
|
||||||
client: client,
|
builder: (context, child) => StreamChat(
|
||||||
child: child,
|
client: client,
|
||||||
streamChatThemeData: StreamChatThemeData(
|
streamChatThemeData: StreamChatThemeData(
|
||||||
colorTheme: ColorTheme.light(
|
colorTheme: StreamColorTheme.light(
|
||||||
primaryAccent: const Color(0xffffe072),
|
accentPrimary: const Color(0xffffe072),
|
||||||
),
|
),
|
||||||
channelTheme: ChannelTheme(
|
channelHeaderTheme: const ChannelHeaderThemeData(
|
||||||
channelHeaderTheme: ChannelHeaderTheme(
|
color: const Color(0xffd34646),
|
||||||
color: const Color(0xffd34646),
|
titleStyle: TextStyle(
|
||||||
title: TextStyle(
|
color: Colors.white,
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
We are creating this class at the very top of our widget tree using the `streamChatThemeData` parameter found in the `StreamChat` widget.
|
We are creating this class at the very top of our widget tree using the `streamChatThemeData` parameter found in the `StreamChat` widget.
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ and send messages.
|
|||||||
```dart
|
```dart
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: StreaChannelHeader(),
|
appBar: const StreamChannelHeader(),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -46,7 +46,7 @@ class ChannelPage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
StreamMessageInput(),
|
const StreamMessageInput(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ common Channels Page.
|
|||||||
```dart
|
```dart
|
||||||
class ChannelListPage extends StatefulWidget {
|
class ChannelListPage extends StatefulWidget {
|
||||||
const ChannelListPage({
|
const ChannelListPage({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
appBar: StreamChannelListHeader(),
|
appBar: const StreamChannelListHeader(),
|
||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
onRefresh: _controller.refresh,
|
onRefresh: _controller.refresh,
|
||||||
child: StreamChannelListView(
|
child: StreamChannelListView(
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ Here is a basic example of the `StreamChannelListView` widget. It consists of th
|
|||||||
```dart
|
```dart
|
||||||
class ChannelListPage extends StatefulWidget {
|
class ChannelListPage extends StatefulWidget {
|
||||||
const ChannelListPage({
|
const ChannelListPage({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ See the [StreamMemberListView](./stream_member_list_view.mdx) documentation for
|
|||||||
```dart
|
```dart
|
||||||
class MemberGridPage extends StatefulWidget {
|
class MemberGridPage extends StatefulWidget {
|
||||||
const MemberGridPage({
|
const MemberGridPage({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final Channel channel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MemberGridPage> createState() => _MemberGridPageState();
|
State<MemberGridPage> createState() => _MemberGridPageState();
|
||||||
@@ -33,13 +33,13 @@ class MemberGridPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _MemberGridPageState extends State<MemberGridPage> {
|
class _MemberGridPageState extends State<MemberGridPage> {
|
||||||
late final _controller = StreamMemberListController(
|
late final _controller = StreamMemberListController(
|
||||||
client: widget.client,
|
channel: widget.channel,
|
||||||
limit: 25,
|
limit: 25,
|
||||||
filter: Filter.and([
|
filter: Filter.and([
|
||||||
Filter.notEqual('id', StreamChat.of(context).currentUser!.id),
|
Filter.notEqual('id', StreamChat.of(context).currentUser!.id),
|
||||||
]),
|
]),
|
||||||
sort: [
|
sort: [
|
||||||
SortOption(
|
const SortOption(
|
||||||
'name',
|
'name',
|
||||||
direction: 1,
|
direction: 1,
|
||||||
),
|
),
|
||||||
@@ -58,13 +58,16 @@ class _MemberGridPageState extends State<MemberGridPage> {
|
|||||||
onRefresh: _controller.refresh,
|
onRefresh: _controller.refresh,
|
||||||
child: StreamMemberGridView(
|
child: StreamMemberGridView(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
onChannelTap: (channel) => Navigator.push(
|
onMemberTap: (member) => Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (_) => StreamChannel(
|
builder: (_) => Scaffold(
|
||||||
channel: channel,
|
body: Center(
|
||||||
child: const ChannelPage(),
|
child: StreamUserAvatar(
|
||||||
),
|
user: member.user!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Make sure to check the [StreamMemberListController](../04-stream_chat_flutter_co
|
|||||||
|
|
||||||
```dart
|
```dart
|
||||||
class MemberListPage extends StatefulWidget {
|
class MemberListPage extends StatefulWidget {
|
||||||
const MemberListPage({Key? key}) : super(key: key);
|
const MemberListPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MemberListPage> createState() => _MemberListPageState();
|
State<MemberListPage> createState() => _MemberListPageState();
|
||||||
@@ -29,7 +29,7 @@ class MemberListPage extends StatefulWidget {
|
|||||||
class _MemberListPageState extends State<MemberListPage> {
|
class _MemberListPageState extends State<MemberListPage> {
|
||||||
late final StreamMemberListController _memberListController =
|
late final StreamMemberListController _memberListController =
|
||||||
StreamMemberListController(
|
StreamMemberListController(
|
||||||
client: StreamChat.of(context).client,
|
channel: StreamChannel.of(context).channel,
|
||||||
limit: 25,
|
limit: 25,
|
||||||
filter: Filter.and(
|
filter: Filter.and(
|
||||||
[Filter.notEqual('id', StreamChat.of(context).currentUser!.id)],
|
[Filter.notEqual('id', StreamChat.of(context).currentUser!.id)],
|
||||||
@@ -62,7 +62,7 @@ You can use your own widget for the member items using the `itemBuilder` paramet
|
|||||||
StreamMemberListView(
|
StreamMemberListView(
|
||||||
// ...
|
// ...
|
||||||
itemBuilder: (context, members, index, defaultWidget) {
|
itemBuilder: (context, members, index, defaultWidget) {
|
||||||
return Text(members[index].name);
|
return Text(members[index].user!.name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ StreamMessageInput(
|
|||||||
InkWell(
|
InkWell(
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.location_on,
|
Icons.location_on,
|
||||||
size: 20.0,
|
size: 20,
|
||||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
color: StreamChatTheme.of(context).colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// Do something here
|
// Do something here
|
||||||
|
|||||||
@@ -29,19 +29,19 @@ An example of how you can use the `StreamMessageListView` is:
|
|||||||
```dart
|
```dart
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: StreamChannelHeader(),
|
appBar: const StreamChannelHeader(),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: StreamMessageListView(),
|
child: StreamMessageListView(),
|
||||||
),
|
),
|
||||||
StreamMessageInput(),
|
const StreamMessageInput(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ Make sure to check the [StreamMessageSearchListView](./stream_message_search_lis
|
|||||||
```dart
|
```dart
|
||||||
class StreamMessageSearchPage extends StatefulWidget {
|
class StreamMessageSearchPage extends StatefulWidget {
|
||||||
const StreamMessageSearchPage({
|
const StreamMessageSearchPage({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);`
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -35,7 +35,10 @@ class _StreamMessageSearchState extends State<StreamMessageSearchPage> {
|
|||||||
late final _controller = StreamMessageSearchListController(
|
late final _controller = StreamMessageSearchListController(
|
||||||
client: widget.client,
|
client: widget.client,
|
||||||
limit: 20,
|
limit: 20,
|
||||||
filters: Filter.in_('members', [StreamChat.of(context).user!.id],),
|
filter: Filter.in_(
|
||||||
|
'members',
|
||||||
|
[StreamChat.of(context).user!.id],
|
||||||
|
),
|
||||||
searchQuery: 'your query here',
|
searchQuery: 'your query here',
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -49,6 +52,9 @@ class _StreamMessageSearchState extends State<StreamMessageSearchPage> {
|
|||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
body: StreamMessageSearchGridView(
|
body: StreamMessageSearchGridView(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
itemBuilder: (context, values, index) {
|
||||||
|
// return your custom widget here
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ While the `StreamMessageListView` is tied to a certain `StreamChannel`, a `Strea
|
|||||||
```dart
|
```dart
|
||||||
class StreamMessageSearchPage extends StatefulWidget {
|
class StreamMessageSearchPage extends StatefulWidget {
|
||||||
const StreamMessageSearchPage({
|
const StreamMessageSearchPage({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);`
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -41,7 +41,10 @@ class _StreamMessageSearchState extends State<StreamMessageSearchPage> {
|
|||||||
late final _controller = StreamMessageSearchListController(
|
late final _controller = StreamMessageSearchListController(
|
||||||
client: widget.client,
|
client: widget.client,
|
||||||
limit: 20,
|
limit: 20,
|
||||||
filters: Filter.in_('members', [StreamChat.of(context).user!.id],),
|
filter: Filter.in_(
|
||||||
|
'members',
|
||||||
|
[StreamChat.of(context).user!.id],
|
||||||
|
),
|
||||||
searchQuery: 'your query here',
|
searchQuery: 'your query here',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ a default implementation of the widget for us to modify.
|
|||||||
```dart
|
```dart
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ Make sure to check the [StreamUserListView](./stream_user_list_view.mdx) documen
|
|||||||
```dart
|
```dart
|
||||||
class UserGridPage extends StatefulWidget {
|
class UserGridPage extends StatefulWidget {
|
||||||
const UserGridPage({
|
const UserGridPage({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ class _UserGridPageState extends State<UserGridPage> {
|
|||||||
Filter.notEqual('id', StreamChat.of(context).currentUser!.id),
|
Filter.notEqual('id', StreamChat.of(context).currentUser!.id),
|
||||||
]),
|
]),
|
||||||
sort: [
|
sort: [
|
||||||
SortOption(
|
const SortOption(
|
||||||
'name',
|
'name',
|
||||||
direction: 1,
|
direction: 1,
|
||||||
),
|
),
|
||||||
@@ -58,12 +58,15 @@ class _UserGridPageState extends State<UserGridPage> {
|
|||||||
onRefresh: _controller.refresh,
|
onRefresh: _controller.refresh,
|
||||||
child: StreamUserGridView(
|
child: StreamUserGridView(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
onChannelTap: (channel) => Navigator.push(
|
onMemberTap: (member) => Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (_) => StreamChannel(
|
builder: (_) => Scaffold(
|
||||||
channel: channel,
|
body: Center(
|
||||||
child: const ChannelPage(),
|
child: StreamUserAvatar(
|
||||||
|
user: member.user!,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Make sure to check the [StreamUserListController](../04-stream_chat_flutter_core
|
|||||||
|
|
||||||
```dart
|
```dart
|
||||||
class UserListPage extends StatefulWidget {
|
class UserListPage extends StatefulWidget {
|
||||||
const UserListPage({Key? key}) : super(key: key);
|
const UserListPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<UserListPage> createState() => _UserListPageState();
|
State<UserListPage> createState() => _UserListPageState();
|
||||||
@@ -66,7 +66,7 @@ You can use your own widget for the user items using the `itemBuilder` parameter
|
|||||||
StreamUsersListView(
|
StreamUsersListView(
|
||||||
// ...
|
// ...
|
||||||
itemBuilder: (context, users, index, defaultWidget) {
|
itemBuilder: (context, users, index, defaultWidget) {
|
||||||
return Text(user[index].name);
|
return Text(users[index].name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ LazyLoadScrollView(
|
|||||||
/// The child could be any widget which dispatches [ScrollNotification]s.
|
/// The child could be any widget which dispatches [ScrollNotification]s.
|
||||||
/// For example [ListView], [GridView] or [CustomScrollView].
|
/// For example [ListView], [GridView] or [CustomScrollView].
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemBuilder: ((context, index) => _buildListTile),
|
itemBuilder: (context, index) => _buildListTile,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ A `MessageListController` is used to paginate data.
|
|||||||
```dart
|
```dart
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -42,20 +42,20 @@ class ChannelPage extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListCore(
|
child: MessageListCore(
|
||||||
emptyBuilder: (context) {
|
emptyBuilder: (context) {
|
||||||
return Center(
|
return const Center(
|
||||||
child: Text('Nothing here...'),
|
child: Text('Nothing here...'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
loadingBuilder: (context) {
|
loadingBuilder: (context) {
|
||||||
return Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
messageListBuilder: (context, list) {
|
messageListBuilder: (context, list) {
|
||||||
return MessagesPage(list);
|
return MessagesPage(list);
|
||||||
},
|
},
|
||||||
errorWidgetBuilder: (context, err) {
|
errorBuilder: (context, err) {
|
||||||
return Center(
|
return const Center(
|
||||||
child: Text('Error'),
|
child: Text('Error'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
+2
-2
@@ -65,7 +65,7 @@ class _MyHomePageState extends State {
|
|||||||
const Text('Usernames:'),
|
const Text('Usernames:'),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: userNames.map((it) => Text(it)).toList(),
|
children: userNames.map(Text.new).toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (nextPageKey != null)
|
if (nextPageKey != null)
|
||||||
@@ -75,7 +75,7 @@ class _MyHomePageState extends State {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
loading: () => CircularProgressIndicator(),
|
loading: CircularProgressIndicator.new,
|
||||||
error: (e) => Text('Error: $e'),
|
error: (e) => Text('Error: $e'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
+4
-2
@@ -25,7 +25,7 @@ First of all we should create an instance of the `StreamChannelListController` a
|
|||||||
You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters.
|
You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
class ChannelListPageState extends State<HomeScreen> {
|
class _MyChannelListPageState extends State<MyChannelListPage> {
|
||||||
/// Controller used for loading more data and controlling pagination in
|
/// Controller used for loading more data and controlling pagination in
|
||||||
/// [StreamChannelListController].
|
/// [StreamChannelListController].
|
||||||
late final channelListController = StreamChannelListController(
|
late final channelListController = StreamChannelListController(
|
||||||
@@ -40,6 +40,8 @@ class ChannelListPageState extends State<HomeScreen> {
|
|||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
...
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Make sure you call `channelListController.doInitialLoad()` to load the initial data and `channelListController.dispose()` when the controller is no longer required.
|
Make sure you call `channelListController.doInitialLoad()` to load the initial data and `channelListController.dispose()` when the controller is no longer required.
|
||||||
@@ -92,7 +94,7 @@ Widget build(BuildContext context) => Scaffold(
|
|||||||
child: Text(error.message),
|
child: Text(error.message),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return CircularProgressIndicator();
|
return const CircularProgressIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
final _item = channels[index];
|
final _item = channels[index];
|
||||||
|
|||||||
+2
-11
@@ -44,20 +44,11 @@ Pass it down to the controller:
|
|||||||
* Mix the `StreamChannelListEventHandler` into your widget state.
|
* Mix the `StreamChannelListEventHandler` into your widget state.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
class _ChannelListPageState extends State<ChannelListPage>
|
class _ChannelListPageState extends State<ChannelListPage> {
|
||||||
with StreamChannelListEventHandler {
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onConnectionRecovered(
|
|
||||||
Event event,
|
|
||||||
StreamChannelListController controller,
|
|
||||||
) {
|
|
||||||
// Write your own custom implementation here
|
|
||||||
}
|
|
||||||
|
|
||||||
late final _listController = StreamChannelListController(
|
late final _listController = StreamChannelListController(
|
||||||
client: StreamChat.of(context).client,
|
client: StreamChat.of(context).client,
|
||||||
eventHandler: this,
|
eventHandler: MyCustomEventHandler(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ return MaterialApp(
|
|||||||
home: HomeScreen(),
|
home: HomeScreen(),
|
||||||
builder: (context, child) => StreamChatCore(
|
builder: (context, child) => StreamChatCore(
|
||||||
client: client,
|
client: client,
|
||||||
child: child!,
|
child: child,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|||||||
+4
-4
@@ -26,7 +26,7 @@ class MemberListPageState extends State<MemberListPage> {
|
|||||||
/// Controller used for loading more data and controlling pagination in
|
/// Controller used for loading more data and controlling pagination in
|
||||||
/// [StreamMemberListController].
|
/// [StreamMemberListController].
|
||||||
late final memberListController = StreamMemberListController(
|
late final memberListController = StreamMemberListController(
|
||||||
client: StreamChatCore.of(context).client,
|
channel: StreamChannel.of(context).channel,
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.m
|
|||||||
```dart
|
```dart
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
body: PagedValueListenableBuilder<int, List<Member>>(
|
body: PagedValueListenableBuilder<int, Member>(
|
||||||
valueListenable: memberListController,
|
valueListenable: memberListController,
|
||||||
builder: (context, value, child) {
|
builder: (context, value, child) {
|
||||||
return value.when(
|
return value.when(
|
||||||
@@ -80,12 +80,12 @@ Widget build(BuildContext context) => Scaffold(
|
|||||||
child: Text(error.message),
|
child: Text(error.message),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return CircularProgressIndicator();
|
return const CircularProgressIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
final _item = members[index];
|
final _item = members[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(_item.name ?? ''),
|
title: Text(_item.user?.name ?? ''),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
+2
-2
@@ -47,7 +47,7 @@ Padding(
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: messageInputController.textEditingController,
|
controller: messageInputController.textFieldController,
|
||||||
onChanged: (s) => messageInputController.text = s,
|
onChanged: (s) => messageInputController.text = s,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
hintText: 'Enter your message',
|
hintText: 'Enter your message',
|
||||||
@@ -66,7 +66,7 @@ Padding(
|
|||||||
messageInputController.message,
|
messageInputController.message,
|
||||||
);
|
);
|
||||||
messageInputController.clear();
|
messageInputController.clear();
|
||||||
if (mounted) {
|
if (context.mounted) {
|
||||||
_updateList();
|
_updateList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -59,8 +59,7 @@ Widget build(BuildContext context) => Scaffold(
|
|||||||
/// In a real-world app you should throttle the search requests.
|
/// In a real-world app you should throttle the search requests.
|
||||||
/// You can use our library [rate_limiter](https://pub.dev/packages/rate_limiter).
|
/// You can use our library [rate_limiter](https://pub.dev/packages/rate_limiter).
|
||||||
onChanged: (s) {
|
onChanged: (s) {
|
||||||
messageSearchListController.searchQuery = s;
|
messageSearchListController..searchQuery = s..doInitialLoad();
|
||||||
messageSearchListController.doInitialLoad();
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -92,7 +91,7 @@ Widget build(BuildContext context) => Scaffold(
|
|||||||
child: Text(error.message),
|
child: Text(error.message),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return CircularProgressIndicator();
|
return const CircularProgressIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
final _item = responses[index];
|
final _item = responses[index];
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.m
|
|||||||
```dart
|
```dart
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
body: PagedValueListenableBuilder<int, List<User>>(
|
body: PagedValueListenableBuilder<int, User>(
|
||||||
valueListenable: userListController,
|
valueListenable: userListController,
|
||||||
builder: (context, value, child) {
|
builder: (context, value, child) {
|
||||||
return value.when(
|
return value.when(
|
||||||
@@ -80,12 +80,12 @@ Widget build(BuildContext context) => Scaffold(
|
|||||||
child: Text(error.message),
|
child: Text(error.message),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return CircularProgressIndicator();
|
return const CircularProgressIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
final _item = users[index];
|
final _item = users[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(_item.name ?? ''),
|
title: Text(_item.name),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -15,16 +15,16 @@ In this guide, you'll explore how you can use Firebase Auth as an authentication
|
|||||||
generate Stream Chat user tokens.
|
generate Stream Chat user tokens.
|
||||||
|
|
||||||
You will use Stream's [NodeJS client](https://getstream.io/chat/docs/node/?language=javascript) for Stream account creation and
|
You will use Stream's [NodeJS client](https://getstream.io/chat/docs/node/?language=javascript) for Stream account creation and
|
||||||
token generation, and [Flutter Cloud Functions for Firebase](https://firebase.flutter.dev/docs/functions/overview) to invoke the cloud functions
|
token generation, and [Flutter Cloud Functions for Firebase](https://firebase.google.com/docs/functions/callable?gen=2nd#dart) to invoke the cloud functions
|
||||||
from your Flutter app.
|
from your Flutter app.
|
||||||
|
|
||||||
Stream supports several different [backend clients](https://getstream.io/chat/sdk/#backend-clients) to integrate with your server. This guide only shows an easy way to integrate Stream Chat authentication using Firebase and Flutter.
|
Stream supports several different [backend clients](https://getstream.io/chat/sdk/#backend-clients) to integrate with your server. This guide only shows an easy way to integrate Stream Chat authentication using Firebase and Flutter.
|
||||||
|
|
||||||
### Flutter Firebase
|
### Flutter Firebase
|
||||||
|
|
||||||
See the [Flutter Firebase getting started](https://firebase.flutter.dev/docs/overview) docs for setup and installation instructions.
|
See the [Flutter Firebase getting started](https://firebase.google.com/docs/flutter/setup) docs for setup and installation instructions.
|
||||||
|
|
||||||
You will also need to add the [Flutter Firebase Authentication](https://firebase.flutter.dev/docs/auth/overview), and [Flutter Firebase Cloud Functions](https://firebase.flutter.dev/docs/functions/overview) packages to your app. Depending on the platform that you target, there may be specific configurations that you need to do.
|
You will also need to add the [Flutter Firebase Authentication](https://firebase.google.com/docs/auth/flutter/start), and [Flutter Firebase Cloud Functions](https://firebase.google.com/docs/functions/callable?gen=2nd#dart) packages to your app. Depending on the platform that you target, there may be specific configurations that you need to do.
|
||||||
|
|
||||||
#### Starting Code
|
#### Starting Code
|
||||||
|
|
||||||
@@ -35,20 +35,20 @@ You will extend this later to execute cloud functions.
|
|||||||
```dart
|
```dart
|
||||||
import 'package:cloud_functions/cloud_functions.dart';
|
import 'package:cloud_functions/cloud_functions.dart';
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:firebase_auth/firebase_auth.dart';
|
import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await Firebase.initializeApp();
|
await Firebase.initializeApp();
|
||||||
runApp(MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return const MaterialApp(
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
body: Auth(),
|
body: Auth(),
|
||||||
),
|
),
|
||||||
@@ -57,20 +57,20 @@ class MyApp extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Auth extends StatefulWidget {
|
class Auth extends StatefulWidget {
|
||||||
Auth({Key? key}) : super(key: key);
|
const Auth({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AuthState createState() => _AuthState();
|
_AuthState createState() => _AuthState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AuthState extends State<Auth> {
|
class _AuthState extends State<Auth> {
|
||||||
late FirebaseAuth auth;
|
late firebase_auth.FirebaseAuth auth;
|
||||||
late FirebaseFunctions functions;
|
late FirebaseFunctions functions;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
auth = FirebaseAuth.instance;
|
auth = firebase_auth.FirebaseAuth.instance;
|
||||||
functions = FirebaseFunctions.instance;
|
functions = FirebaseFunctions.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,19 +103,26 @@ class _AuthState extends State<Auth> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
AuthenticationState(
|
AuthenticationState(
|
||||||
streamUser: auth.authStateChanges(),
|
streamUser: auth.authStateChanges().map(
|
||||||
|
(firebaseUser) => firebaseUser != null
|
||||||
|
? User(
|
||||||
|
id: firebaseUser.uid,
|
||||||
|
// Map other user fields here
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: createAccount,
|
onPressed: createAccount,
|
||||||
child: Text('Create account'),
|
child: const Text('Create account'),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: signIn,
|
onPressed: signIn,
|
||||||
child: Text('Sign in'),
|
child: const Text('Sign in'),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: signOut,
|
onPressed: signOut,
|
||||||
child: Text('Sign out'),
|
child: const Text('Sign out'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -125,9 +132,9 @@ class _AuthState extends State<Auth> {
|
|||||||
|
|
||||||
class AuthenticationState extends StatelessWidget {
|
class AuthenticationState extends StatelessWidget {
|
||||||
const AuthenticationState({
|
const AuthenticationState({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.streamUser,
|
required this.streamUser,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final Stream<User?> streamUser;
|
final Stream<User?> streamUser;
|
||||||
|
|
||||||
@@ -138,10 +145,10 @@ class AuthenticationState extends StatelessWidget {
|
|||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
return (snapshot.data != null)
|
return (snapshot.data != null)
|
||||||
? Text('Authenticated')
|
? const Text('Authenticated')
|
||||||
: Text('Not Authenticated');
|
: const Text('Not Authenticated');
|
||||||
}
|
}
|
||||||
return Text('Not Authenticated');
|
return const Text('Not Authenticated');
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -158,8 +165,8 @@ in the `createAccount`, `signIn` and `signOut` methods. There is a button to inv
|
|||||||
|
|
||||||
The `FirebaseFunctions.instance` will be used later in this guide.
|
The `FirebaseFunctions.instance` will be used later in this guide.
|
||||||
|
|
||||||
The `AuthenticationState` widget listens to `auth.authStateChanges()` to display a message
|
The `AuthenticationState`` widget listens to `auth.authStateChanges()` (mapped to Stream's `User`)
|
||||||
indicating if a user is authenticated.
|
to display a message indicating if a user is authenticated.
|
||||||
|
|
||||||
### Firebase Cloud Functions
|
### Firebase Cloud Functions
|
||||||
|
|
||||||
@@ -168,7 +175,7 @@ Firebase Cloud Functions allows you to extend Firebase with custom operations th
|
|||||||
- **External event**: For example, directly calling a cloud function from your Flutter application.
|
- **External event**: For example, directly calling a cloud function from your Flutter application.
|
||||||
|
|
||||||
To set up your local environment to deploy cloud functions, please see the
|
To set up your local environment to deploy cloud functions, please see the
|
||||||
[Cloud Functions getting started](https://firebase.flutter.dev/docs/overview) docs.
|
[Cloud Functions getting started](https://firebase.google.com/docs/flutter/setup) docs.
|
||||||
|
|
||||||
After initializing your project with cloud functions, you should have a **functions** folder in your project, including a `package.json` file.
|
After initializing your project with cloud functions, you should have a **functions** folder in your project, including a `package.json` file.
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
|
|
||||||
|
// Setup client and channel code here
|
||||||
|
...
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
|||||||
+3
-3
@@ -208,9 +208,9 @@ void handleNotification(
|
|||||||
|
|
||||||
flutterLocalNotificationsPlugin.show(
|
flutterLocalNotificationsPlugin.show(
|
||||||
1,
|
1,
|
||||||
'New message from ${response.message.user.name} in ${response.channel.name}',
|
'New message from ${response.message.user!.name} in ${response.channel!.name}',
|
||||||
response.message.text,
|
response.message.text,
|
||||||
NotificationDetails(
|
const NotificationDetails(
|
||||||
android: AndroidNotificationDetails(
|
android: AndroidNotificationDetails(
|
||||||
'new_message',
|
'new_message',
|
||||||
'New message notifications channel',
|
'New message notifications channel',
|
||||||
@@ -255,7 +255,7 @@ Make sure to read the [general push notification docs](https://getstream.io/chat
|
|||||||
If you're not sure whether you've set up push notifications correctly, for example, you don't always receive them, or they don’t work reliably, then you can follow these steps to make sure your configuration is correct and working:
|
If you're not sure whether you've set up push notifications correctly, for example, you don't always receive them, or they don’t work reliably, then you can follow these steps to make sure your configuration is correct and working:
|
||||||
|
|
||||||
1. Clone our repository for push testing: `git clone [email protected]:GetStream/chat-push-test.git`
|
1. Clone our repository for push testing: `git clone [email protected]:GetStream/chat-push-test.git`
|
||||||
2. `cd flutter`
|
2. `cd chat-push-test/flutter`
|
||||||
3. In that folder run `flutter pub get`
|
3. In that folder run `flutter pub get`
|
||||||
4. Input your API key and secret in `lib/main.dart`
|
4. Input your API key and secret in `lib/main.dart`
|
||||||
5. Change the bundle identifier/application ID and development team/user so you can run the app on your physical device.**Do not** run on an iOS simulator, as it will not work. Testing on an Android emulator is fine.
|
5. Change the bundle identifier/application ID and development team/user so you can run the app on your physical device.**Do not** run on an iOS simulator, as it will not work. Testing on an Android emulator is fine.
|
||||||
|
|||||||
@@ -489,47 +489,51 @@ class _MyAppState extends State<MyApp> {
|
|||||||
|
|
||||||
late final _router = GoRouter(
|
late final _router = GoRouter(
|
||||||
initialLocation: '/',
|
initialLocation: '/',
|
||||||
navigatorBuilder: (context, state, child) {
|
|
||||||
if (state.location.startsWith('/chat')) {
|
|
||||||
wasPreviousRouteChat = true;
|
|
||||||
return StreamChat(
|
|
||||||
client: _client,
|
|
||||||
child: ChatSetup(client: _client, child: child),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (wasPreviousRouteChat) {
|
|
||||||
wasPreviousRouteChat = false;
|
|
||||||
return StreamChat(
|
|
||||||
client: _client,
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
ShellRoute(
|
||||||
path: '/',
|
builder: (context, state, child) {
|
||||||
builder: (context, state) => const HomeScreen(),
|
if (state.uri.host.startsWith('/chat')) {
|
||||||
|
wasPreviousRouteChat = true;
|
||||||
|
return StreamChat(
|
||||||
|
client: _client,
|
||||||
|
child: ChatSetup(client: _client, child: child),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (wasPreviousRouteChat) {
|
||||||
|
wasPreviousRouteChat = false;
|
||||||
|
return StreamChat(
|
||||||
|
client: _client,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'settings',
|
path: '/',
|
||||||
builder: (context, state) => const SettingsPage(),
|
builder: (context, state) => const HomeScreen(),
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: 'chat',
|
|
||||||
builder: (context, state) => const ChannelListPage(),
|
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'channel',
|
path: 'settings',
|
||||||
builder: (context, state) {
|
builder: (context, state) => const SettingsPage(),
|
||||||
final channel = state.extra as Channel;
|
),
|
||||||
return StreamChannel(
|
GoRoute(
|
||||||
channel: channel,
|
path: 'chat',
|
||||||
child: const ChannelPage(),
|
builder: (context, state) => const ChannelListPage(),
|
||||||
);
|
routes: [
|
||||||
},
|
GoRoute(
|
||||||
|
path: 'channel',
|
||||||
|
builder: (context, state) {
|
||||||
|
final channel = state.extra as Channel;
|
||||||
|
return StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: const ChannelPage(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
# 6.10.0
|
||||||
|
|
||||||
|
🐞 Fixed
|
||||||
|
|
||||||
|
- [[#1753]](https://github.com/GetStream/stream-chat-flutter/issues/1753) Fixed Unhandled null
|
||||||
|
check operator exception when user is removed from a channel.
|
||||||
|
|
||||||
## 6.9.0
|
## 6.9.0
|
||||||
|
|
||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
|
|||||||
@@ -1658,7 +1658,7 @@ class ClientState {
|
|||||||
)
|
)
|
||||||
.listen((event) async {
|
.listen((event) async {
|
||||||
final isCurrentUser = event.user!.id == currentUser!.id;
|
final isCurrentUser = event.user!.id == currentUser!.id;
|
||||||
if (isCurrentUser) {
|
if (isCurrentUser && event.channel != null) {
|
||||||
final eventChannel = event.channel!;
|
final eventChannel = event.channel!;
|
||||||
await _client.chatPersistenceClient
|
await _client.chatPersistenceClient
|
||||||
?.deleteChannels([eventChannel.cid]);
|
?.deleteChannels([eventChannel.cid]);
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ class StreamHttpClientOptions {
|
|||||||
/// Instantiates a new [StreamHttpClientOptions]
|
/// Instantiates a new [StreamHttpClientOptions]
|
||||||
const StreamHttpClientOptions({
|
const StreamHttpClientOptions({
|
||||||
String? baseUrl,
|
String? baseUrl,
|
||||||
this.connectTimeout = const Duration(seconds: 6),
|
this.connectTimeout = const Duration(seconds: 30),
|
||||||
this.receiveTimeout = const Duration(seconds: 6),
|
this.receiveTimeout = const Duration(seconds: 30),
|
||||||
this.queryParameters = const {},
|
this.queryParameters = const {},
|
||||||
this.headers = const {},
|
this.headers = const {},
|
||||||
}) : baseUrl = baseUrl ?? _defaultBaseURL;
|
}) : baseUrl = baseUrl ?? _defaultBaseURL;
|
||||||
@@ -16,10 +16,10 @@ class StreamHttpClientOptions {
|
|||||||
/// base url to use with client.
|
/// base url to use with client.
|
||||||
final String baseUrl;
|
final String baseUrl;
|
||||||
|
|
||||||
/// connect timeout, default to 6s
|
/// connect timeout, default to 30s
|
||||||
final Duration connectTimeout;
|
final Duration connectTimeout;
|
||||||
|
|
||||||
/// received timeout, default to 6s
|
/// received timeout, default to 30s
|
||||||
final Duration receiveTimeout;
|
final Duration receiveTimeout;
|
||||||
|
|
||||||
/// Common query parameters.
|
/// Common query parameters.
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ import 'package:stream_chat/src/client/client.dart';
|
|||||||
/// Current package version
|
/// Current package version
|
||||||
/// Used in [StreamChatClient] to build the `x-stream-client` header
|
/// Used in [StreamChatClient] to build the `x-stream-client` header
|
||||||
// ignore: constant_identifier_names
|
// ignore: constant_identifier_names
|
||||||
const PACKAGE_VERSION = '6.9.0';
|
const PACKAGE_VERSION = '6.10.0';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: stream_chat
|
name: stream_chat
|
||||||
homepage: https://getstream.io/
|
homepage: https://getstream.io/
|
||||||
description: The official Dart client for Stream Chat, a service for building chat applications.
|
description: The official Dart client for Stream Chat, a service for building chat applications.
|
||||||
version: 6.9.0
|
version: 6.10.0
|
||||||
repository: https://github.com/GetStream/stream-chat-flutter
|
repository: https://github.com/GetStream/stream-chat-flutter
|
||||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ void main() {
|
|||||||
test('should return the all default set params', () {
|
test('should return the all default set params', () {
|
||||||
const options = StreamHttpClientOptions();
|
const options = StreamHttpClientOptions();
|
||||||
expect(options.baseUrl, 'https://chat.stream-io-api.com');
|
expect(options.baseUrl, 'https://chat.stream-io-api.com');
|
||||||
expect(options.connectTimeout, const Duration(seconds: 6));
|
expect(options.connectTimeout, const Duration(seconds: 30));
|
||||||
expect(options.receiveTimeout, const Duration(seconds: 6));
|
expect(options.receiveTimeout, const Duration(seconds: 30));
|
||||||
expect(options.queryParameters, const {});
|
expect(options.queryParameters, const {});
|
||||||
expect(options.headers, const {});
|
expect(options.headers, const {});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -164,7 +164,8 @@ void main() {
|
|||||||
expect(
|
expect(
|
||||||
e.message,
|
e.message,
|
||||||
"The connection errored: Dio can't establish a new connection"
|
"The connection errored: Dio can't establish a new connection"
|
||||||
' after it was closed.',
|
' after it was closed. This indicates an error which most likely'
|
||||||
|
' cannot be solved by the library.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
# 6.12.0
|
||||||
|
|
||||||
|
🐞 Fixed
|
||||||
|
|
||||||
|
- [[#1759]](https://github.com/GetStream/stream-chat-flutter/issues/1759) Fixed
|
||||||
|
The Reaction Picker is not being removed when I set showReactionPicker to false.
|
||||||
|
|
||||||
# 6.11.0
|
# 6.11.0
|
||||||
|
|
||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'package:stream_chat_flutter_example/debug/error_dialog.dart';
|
||||||
|
|
||||||
|
class DebugAddUser extends StatelessWidget {
|
||||||
|
const DebugAddUser({
|
||||||
|
super.key,
|
||||||
|
required this.client,
|
||||||
|
required this.channel,
|
||||||
|
});
|
||||||
|
|
||||||
|
final StreamChatClient client;
|
||||||
|
final Channel channel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Add User',
|
||||||
|
hintText: 'User Id',
|
||||||
|
isDense: true,
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
onSubmitted: (value) async {
|
||||||
|
final userId = value.trim();
|
||||||
|
try {
|
||||||
|
debugPrint('[addUser] userId: $userId');
|
||||||
|
final result = await client.addChannelMembers(
|
||||||
|
channel.id!,
|
||||||
|
channel.type,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
debugPrint('[addUser] result: $result');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('[addUser] failed: $e');
|
||||||
|
showErrorDialog(context, e, 'Add User');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'package:stream_chat_flutter_example/debug/error_dialog.dart';
|
||||||
|
|
||||||
|
class DebugRemoveUser extends StatelessWidget {
|
||||||
|
const DebugRemoveUser({
|
||||||
|
super.key,
|
||||||
|
required this.client,
|
||||||
|
required this.channel,
|
||||||
|
});
|
||||||
|
|
||||||
|
final StreamChatClient client;
|
||||||
|
final Channel channel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Remove User',
|
||||||
|
hintText: 'User Id',
|
||||||
|
isDense: true,
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
onSubmitted: (value) async {
|
||||||
|
final userId = value.trim();
|
||||||
|
try {
|
||||||
|
debugPrint('[removeUser] userId: $userId');
|
||||||
|
final result = await client.removeChannelMembers(
|
||||||
|
channel.id!,
|
||||||
|
channel.type,
|
||||||
|
[userId],
|
||||||
|
);
|
||||||
|
debugPrint('[removeUser] result: $result');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('[removeUser] failed: $e');
|
||||||
|
showErrorDialog(context, e, 'Remove User');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,11 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
import 'package:stream_chat_flutter_example/debug/actions/add_user.dart';
|
||||||
import 'package:stream_chat_flutter_example/debug/actions/ban_user.dart';
|
import 'package:stream_chat_flutter_example/debug/actions/ban_user.dart';
|
||||||
import 'package:stream_chat_flutter_example/debug/actions/mute_user.dart';
|
import 'package:stream_chat_flutter_example/debug/actions/mute_user.dart';
|
||||||
import 'package:stream_chat_flutter_example/debug/actions/remove_shadow_ban.dart';
|
import 'package:stream_chat_flutter_example/debug/actions/remove_shadow_ban.dart';
|
||||||
|
import 'package:stream_chat_flutter_example/debug/actions/remove_user.dart';
|
||||||
import 'package:stream_chat_flutter_example/debug/actions/shadow_ban.dart';
|
import 'package:stream_chat_flutter_example/debug/actions/shadow_ban.dart';
|
||||||
import 'package:stream_chat_flutter_example/debug/actions/unban_user.dart';
|
import 'package:stream_chat_flutter_example/debug/actions/unban_user.dart';
|
||||||
import 'package:stream_chat_flutter_example/debug/actions/unmute_user.dart';
|
import 'package:stream_chat_flutter_example/debug/actions/unmute_user.dart';
|
||||||
@@ -82,6 +84,10 @@ class _DebugChannelPageState extends State<DebugChannelPage> {
|
|||||||
DebugShadowBan(client: _channel.client),
|
DebugShadowBan(client: _channel.client),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
DebugRemoveShadowBan(client: _channel.client),
|
DebugRemoveShadowBan(client: _channel.client),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
DebugAddUser(client: _channel.client, channel: _channel),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
DebugRemoveUser(client: _channel.client, channel: _channel),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
bool? showReactionPicker,
|
bool? showReactionPicker,
|
||||||
@Deprecated('Use `showReactionPicker` instead')
|
@Deprecated('Use `showReactionPicker` instead')
|
||||||
bool showReactionPickerIndicator = true,
|
bool showReactionPickerIndicator = true,
|
||||||
@internal this.showReactionPickerTail = false,
|
@internal
|
||||||
|
@Deprecated('Use `showReactionPicker` instead')
|
||||||
|
this.showReactionPickerTail,
|
||||||
this.showUserAvatar = DisplayWidget.show,
|
this.showUserAvatar = DisplayWidget.show,
|
||||||
this.showSendingIndicator = true,
|
this.showSendingIndicator = true,
|
||||||
this.showThreadReplyIndicator = false,
|
this.showThreadReplyIndicator = false,
|
||||||
@@ -483,7 +485,8 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
/// Whether or not to show the reaction picker tail
|
/// Whether or not to show the reaction picker tail
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
@internal
|
@internal
|
||||||
final bool showReactionPickerTail;
|
@Deprecated('Use `showReactionPicker` instead')
|
||||||
|
final bool? showReactionPickerTail;
|
||||||
|
|
||||||
/// {@template onShowMessage}
|
/// {@template onShowMessage}
|
||||||
/// Callback when show message is tapped
|
/// Callback when show message is tapped
|
||||||
@@ -743,8 +746,6 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
showReactionPicker: showReactionPicker ??
|
showReactionPicker: showReactionPicker ??
|
||||||
showReactionPickerIndicator ??
|
showReactionPickerIndicator ??
|
||||||
this.showReactionPicker,
|
this.showReactionPicker,
|
||||||
showReactionPickerTail:
|
|
||||||
showReactionPickerTail ?? this.showReactionPickerTail,
|
|
||||||
onShowMessage: onShowMessage ?? this.onShowMessage,
|
onShowMessage: onShowMessage ?? this.onShowMessage,
|
||||||
showUsername: showUsername ?? this.showUsername,
|
showUsername: showUsername ?? this.showUsername,
|
||||||
showTimestamp: showTimestamp ?? this.showTimestamp,
|
showTimestamp: showTimestamp ?? this.showTimestamp,
|
||||||
@@ -1002,7 +1003,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
messageWidget: widget,
|
messageWidget: widget,
|
||||||
showBottomRow: showBottomRow,
|
showBottomRow: showBottomRow,
|
||||||
showPinHighlight: widget.showPinHighlight,
|
showPinHighlight: widget.showPinHighlight,
|
||||||
showReactionPickerTail: widget.showReactionPickerTail,
|
showReactionPickerTail: widget.showReactionPicker,
|
||||||
showReactions: showReactions,
|
showReactions: showReactions,
|
||||||
onReactionsTap: () {
|
onReactionsTap: () {
|
||||||
widget.onReactionsTap != null
|
widget.onReactionsTap != null
|
||||||
@@ -1217,7 +1218,8 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
translateUserAvatar: false,
|
translateUserAvatar: false,
|
||||||
showSendingIndicator: false,
|
showSendingIndicator: false,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
// Show the tail if the reaction picker is visible.
|
// Show both the tail if the picker is shown.
|
||||||
|
showReactionPicker: widget.showReactionPicker,
|
||||||
showReactionPickerTail: widget.showReactionPicker,
|
showReactionPickerTail: widget.showReactionPicker,
|
||||||
showPinHighlight: false,
|
showPinHighlight: false,
|
||||||
showUserAvatar:
|
showUserAvatar:
|
||||||
@@ -1258,6 +1260,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
return StreamChannel(
|
return StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: MessageActionsModal(
|
child: MessageActionsModal(
|
||||||
|
showReactionPicker: widget.showReactionPicker,
|
||||||
messageWidget: widget.copyWith(
|
messageWidget: widget.copyWith(
|
||||||
key: const Key('MessageWidget'),
|
key: const Key('MessageWidget'),
|
||||||
message: widget.message.copyWith(
|
message: widget.message.copyWith(
|
||||||
@@ -1271,9 +1274,6 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
translateUserAvatar: false,
|
translateUserAvatar: false,
|
||||||
showSendingIndicator: false,
|
showSendingIndicator: false,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
// Show both the tail if the picker is shown.
|
|
||||||
showReactionPicker: widget.showReactionPicker,
|
|
||||||
showReactionPickerTail: widget.showReactionPicker,
|
|
||||||
showPinHighlight: false,
|
showPinHighlight: false,
|
||||||
showUserAvatar: widget.message.user!.id ==
|
showUserAvatar: widget.message.user!.id ==
|
||||||
channel.client.state.currentUser!.id
|
channel.client.state.currentUser!.id
|
||||||
|
|||||||
@@ -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: 6.11.0
|
version: 6.12.0
|
||||||
repository: https://github.com/GetStream/stream-chat-flutter
|
repository: https://github.com/GetStream/stream-chat-flutter
|
||||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ dependencies:
|
|||||||
diacritic: ^0.1.4
|
diacritic: ^0.1.4
|
||||||
dio: ^5.3.2
|
dio: ^5.3.2
|
||||||
ezanimation: ^0.6.0
|
ezanimation: ^0.6.0
|
||||||
file_picker: ^5.3.3
|
file_picker: ">=5.3.3 <7.0.0"
|
||||||
file_selector: ^1.0.0
|
file_selector: ^1.0.0
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
@@ -38,7 +38,7 @@ dependencies:
|
|||||||
rxdart: ^0.27.7
|
rxdart: ^0.27.7
|
||||||
share_plus: ">=7.1.0 <9.0.0"
|
share_plus: ">=7.1.0 <9.0.0"
|
||||||
shimmer: ^3.0.0
|
shimmer: ^3.0.0
|
||||||
stream_chat_flutter_core: ^6.10.0
|
stream_chat_flutter_core: ^6.11.0
|
||||||
synchronized: ^3.1.0
|
synchronized: ^3.1.0
|
||||||
thumblr: ^0.0.4
|
thumblr: ^0.0.4
|
||||||
url_launcher: ^6.1.12
|
url_launcher: ^6.1.12
|
||||||
|
|||||||
+95
@@ -64,6 +64,101 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show the reaction picker',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel(
|
||||||
|
ownCapabilities: ['send-message', 'send-reaction'],
|
||||||
|
);
|
||||||
|
|
||||||
|
when(() => client.state).thenReturn(clientState);
|
||||||
|
when(() => clientState.currentUser).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.fromTheme(themeData);
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: SizedBox(
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
state: MessageState.sent,
|
||||||
|
),
|
||||||
|
messageWidget: const Text(
|
||||||
|
'test',
|
||||||
|
key: Key('MessageWidget'),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(StreamReactionPicker), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should not show the reaction picker',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(() => client.state).thenReturn(clientState);
|
||||||
|
when(() => clientState.currentUser).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.fromTheme(themeData);
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: SizedBox(
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: MessageActionsModal(
|
||||||
|
showReactionPicker: false,
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
state: MessageState.sent,
|
||||||
|
),
|
||||||
|
messageWidget: const Text(
|
||||||
|
'test',
|
||||||
|
key: Key('MessageWidget'),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(StreamReactionPicker), findsNothing);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'it should show some actions',
|
'it should show some actions',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
|
|||||||
@@ -14,6 +14,13 @@ class MockClient extends Mock implements StreamChatClient {
|
|||||||
class MockClientState extends Mock implements ClientState {}
|
class MockClientState extends Mock implements ClientState {}
|
||||||
|
|
||||||
class MockChannel extends Mock implements Channel {
|
class MockChannel extends Mock implements Channel {
|
||||||
|
MockChannel({
|
||||||
|
this.ownCapabilities = const ['send-message'],
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
final List<String> ownCapabilities;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> get initialized async => true;
|
Future<bool> get initialized async => true;
|
||||||
|
|
||||||
@@ -22,9 +29,6 @@ class MockChannel extends Mock implements Channel {
|
|||||||
Future<void> keyStroke([String? parentId]) async {
|
Future<void> keyStroke([String? parentId]) async {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
List<String> get ownCapabilities => ['send-message'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockChannelState extends Mock implements ChannelClientState {
|
class MockChannelState extends Mock implements ChannelClientState {
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## 6.11.0
|
||||||
|
|
||||||
|
🐞 Fixed
|
||||||
|
|
||||||
|
- Fixed video attachment uploading. [#1754](https://github.com/GetStream/stream-chat-flutter/pull/1754)
|
||||||
|
|
||||||
## 6.10.0
|
## 6.10.0
|
||||||
|
|
||||||
- Added mixin support to `StreamChannelListEventHandler`.
|
- Added mixin support to `StreamChannelListEventHandler`.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: stream_chat_flutter_core
|
name: stream_chat_flutter_core
|
||||||
homepage: https://github.com/GetStream/stream-chat-flutter
|
homepage: https://github.com/GetStream/stream-chat-flutter
|
||||||
description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter.
|
description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter.
|
||||||
version: 6.10.0
|
version: 6.11.0
|
||||||
repository: https://github.com/GetStream/stream-chat-flutter
|
repository: https://github.com/GetStream/stream-chat-flutter
|
||||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||||
|
|
||||||
@@ -11,13 +11,13 @@ environment:
|
|||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
collection: ^1.17.1
|
collection: ^1.17.1
|
||||||
connectivity_plus: ^4.0.2
|
connectivity_plus: ">=4.0.2 <6.0.0"
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
freezed_annotation: ^2.4.1
|
freezed_annotation: ^2.4.1
|
||||||
meta: ^1.9.1
|
meta: ^1.9.1
|
||||||
rxdart: ^0.27.7
|
rxdart: ^0.27.7
|
||||||
stream_chat: ^6.9.0
|
stream_chat: ^6.10.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.6
|
build_runner: ^2.4.6
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
## 5.12.0
|
||||||
|
|
||||||
|
* Updated `stream_chat_flutter` dependency to [`6.12.0`](https://pub.dev/packages/stream_chat_flutter/changelog).
|
||||||
|
|
||||||
## 5.11.0
|
## 5.11.0
|
||||||
|
|
||||||
* Updated `stream_chat_flutter` dependency to [`6.11.0`](https://pub.dev/packages/stream_chat_flutter/changelog).
|
* Updated `stream_chat_flutter` dependency to [`6.11.0`](https://pub.dev/packages/stream_chat_flutter/changelog).
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: stream_chat_localizations
|
name: stream_chat_localizations
|
||||||
description: The Official localizations for Stream Chat Flutter, a service for building chat applications
|
description: The Official localizations for Stream Chat Flutter, a service for building chat applications
|
||||||
version: 5.11.0
|
version: 5.12.0
|
||||||
homepage: https://github.com/GetStream/stream-chat-flutter
|
homepage: https://github.com/GetStream/stream-chat-flutter
|
||||||
repository: https://github.com/GetStream/stream-chat-flutter
|
repository: https://github.com/GetStream/stream-chat-flutter
|
||||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||||
@@ -14,7 +14,7 @@ dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
stream_chat_flutter: ^6.11.0
|
stream_chat_flutter: ^6.12.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
## 6.10.0
|
||||||
|
|
||||||
|
- Updated `stream_chat` dependency to [`6.10.0`](https://pub.dev/packages/stream_chat/changelog).
|
||||||
|
|
||||||
## 6.9.0
|
## 6.9.0
|
||||||
|
|
||||||
- Updated `stream_chat` dependency to [`6.9.0`](https://pub.dev/packages/stream_chat/changelog).
|
- Updated `stream_chat` dependency to [`6.9.0`](https://pub.dev/packages/stream_chat/changelog).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: stream_chat_persistence
|
name: stream_chat_persistence
|
||||||
homepage: https://github.com/GetStream/stream-chat-flutter
|
homepage: https://github.com/GetStream/stream-chat-flutter
|
||||||
description: Official Stream Chat Persistence library. Build your own chat experience using Dart and Flutter.
|
description: Official Stream Chat Persistence library. Build your own chat experience using Dart and Flutter.
|
||||||
version: 6.9.0
|
version: 6.10.0
|
||||||
repository: https://github.com/GetStream/stream-chat-flutter
|
repository: https://github.com/GetStream/stream-chat-flutter
|
||||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ dependencies:
|
|||||||
path: ^1.8.3
|
path: ^1.8.3
|
||||||
path_provider: ^2.1.0
|
path_provider: ^2.1.0
|
||||||
sqlite3_flutter_libs: ^0.5.15
|
sqlite3_flutter_libs: ^0.5.15
|
||||||
stream_chat: ^6.9.0
|
stream_chat: ^6.10.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.6
|
build_runner: ^2.4.6
|
||||||
|
|||||||
Reference in New Issue
Block a user