Merge remote-tracking branch 'origin/develop' into feat/localization
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
## Upcoming
|
||||||
|
|
||||||
|
🐞 Fixed
|
||||||
|
|
||||||
|
- [#563](https://github.com/GetStream/stream-chat-flutter/issues/563): `Channel.stopWatching()` not working
|
||||||
|
|
||||||
## 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
🛑️ Breaking Changes from `1.5.3`
|
🛑️ Breaking Changes from `1.5.3`
|
||||||
@@ -619,4 +625,4 @@
|
|||||||
|
|
||||||
## 0.0.2
|
## 0.0.2
|
||||||
|
|
||||||
- first beta version
|
- first beta version
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
## Upcoming
|
## Upcoming
|
||||||
|
|
||||||
✅ Added
|
✅ Added
|
||||||
|
|
||||||
|
- Added `MessageListView.paginationLimit`
|
||||||
- Allow the various ListView widgets to be themed via ThemeData classes
|
- Allow the various ListView widgets to be themed via ThemeData classes
|
||||||
|
|
||||||
|
🐞 Fixed
|
||||||
|
|
||||||
|
- Fix floating date divider not having a fixed size
|
||||||
|
|
||||||
## 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
🛑️ Breaking Changes from `1.5.4`
|
🛑️ Breaking Changes from `1.5.4`
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
|
|||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 30
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
@@ -41,7 +41,7 @@ android {
|
|||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "com.example.example"
|
applicationId "com.example.example"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 30
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.3.50'
|
ext.kotlin_version = '1.5.20'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.6.2'
|
classpath 'com.android.tools.build:gradle:4.2.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip
|
||||||
|
|||||||
@@ -166,11 +166,23 @@ class MessageListView extends StatefulWidget {
|
|||||||
this.showFloatingDateDivider = true,
|
this.showFloatingDateDivider = true,
|
||||||
this.threadSeparatorBuilder,
|
this.threadSeparatorBuilder,
|
||||||
this.messageListController,
|
this.messageListController,
|
||||||
|
this.reverse = true,
|
||||||
|
this.paginationLimit = 20,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// Function used to build a custom message widget
|
/// Function used to build a custom message widget
|
||||||
final MessageBuilder? messageBuilder;
|
final MessageBuilder? messageBuilder;
|
||||||
|
|
||||||
|
/// Whether the view scrolls in the reading direction.
|
||||||
|
///
|
||||||
|
/// Defaults to true.
|
||||||
|
///
|
||||||
|
/// See [ScrollView.reverse].
|
||||||
|
final bool reverse;
|
||||||
|
|
||||||
|
/// Limit used during pagination
|
||||||
|
final int paginationLimit;
|
||||||
|
|
||||||
/// Function used to build a custom system message widget
|
/// Function used to build a custom system message widget
|
||||||
final SystemMessageBuilder? systemMessageBuilder;
|
final SystemMessageBuilder? systemMessageBuilder;
|
||||||
|
|
||||||
@@ -329,6 +341,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => MessageListCore(
|
Widget build(BuildContext context) => MessageListCore(
|
||||||
|
paginationLimit: widget.paginationLimit,
|
||||||
messageFilter: widget.messageFilter,
|
messageFilter: widget.messageFilter,
|
||||||
loadingBuilder: widget.loadingBuilder ??
|
loadingBuilder: widget.loadingBuilder ??
|
||||||
(context) => const Center(
|
(context) => const Center(
|
||||||
@@ -446,7 +459,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
initialAlignment: initialAlignment ?? 0,
|
initialAlignment: initialAlignment ?? 0,
|
||||||
physics: widget.scrollPhysics,
|
physics: widget.scrollPhysics,
|
||||||
itemScrollController: _scrollController,
|
itemScrollController: _scrollController,
|
||||||
reverse: true,
|
reverse: widget.reverse,
|
||||||
addAutomaticKeepAlives: false,
|
addAutomaticKeepAlives: false,
|
||||||
itemCount: itemCount,
|
itemCount: itemCount,
|
||||||
|
|
||||||
@@ -622,7 +635,8 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Positioned _buildFloatingDateDivider(int itemCount) => Positioned(
|
Positioned _buildFloatingDateDivider(int itemCount) => Positioned(
|
||||||
top: 20,
|
top: widget.reverse ? 20 : null,
|
||||||
|
bottom: widget.reverse ? null : 20,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
child: BetterStreamBuilder<Iterable<ItemPosition>>(
|
child: BetterStreamBuilder<Iterable<ItemPosition>>(
|
||||||
@@ -656,7 +670,9 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Future<void> _paginateData(
|
Future<void> _paginateData(
|
||||||
StreamChannelState? channel, QueryDirection direction) =>
|
StreamChannelState? channel,
|
||||||
|
QueryDirection direction,
|
||||||
|
) =>
|
||||||
_messageListController.paginateData!(direction: direction);
|
_messageListController.paginateData!(direction: direction);
|
||||||
|
|
||||||
int? _getTopElementIndex(Iterable<ItemPosition> values) {
|
int? _getTopElementIndex(Iterable<ItemPosition> values) {
|
||||||
@@ -716,9 +732,13 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: StreamSvgIcon.down(
|
child: widget.reverse
|
||||||
color: _streamTheme.colorTheme.textHighEmphasis,
|
? StreamSvgIcon.down(
|
||||||
),
|
color: _streamTheme.colorTheme.textHighEmphasis,
|
||||||
|
)
|
||||||
|
: StreamSvgIcon.up(
|
||||||
|
color: _streamTheme.colorTheme.textHighEmphasis,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (showUnreadCount)
|
if (showUnreadCount)
|
||||||
Positioned(
|
Positioned(
|
||||||
|
|||||||
@@ -37,6 +37,18 @@ class StreamSvgIcon extends StatelessWidget {
|
|||||||
height: size,
|
height: size,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// [StreamSvgIcon] type
|
||||||
|
factory StreamSvgIcon.up({
|
||||||
|
double? size,
|
||||||
|
Color? color,
|
||||||
|
}) =>
|
||||||
|
StreamSvgIcon(
|
||||||
|
assetName: 'Icon_up.svg',
|
||||||
|
color: color,
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
);
|
||||||
|
|
||||||
/// [StreamSvgIcon] type
|
/// [StreamSvgIcon] type
|
||||||
factory StreamSvgIcon.attach({
|
factory StreamSvgIcon.attach({
|
||||||
double? size,
|
double? size,
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path transform="translate(24, 24) rotate(-180)" d="M5.30605 8.30597C5.11052 8.50222 5.00073 8.76795 5.00073 9.04498C5.00073 9.322 5.11052 9.58774 5.30605 9.78398L11.2061 15.697C11.4321 15.923 11.7351 16.024 12.0291 16C12.17 16.0032 12.3102 15.9778 12.441 15.9252C12.5718 15.8726 12.6906 15.7939 12.7901 15.694L18.6941 9.78398C18.8898 9.58786 18.9998 9.32208 18.9998 9.04498C18.9998 8.76787 18.8898 8.50209 18.6941 8.30597C18.5972 8.20898 18.4821 8.13203 18.3555 8.07952C18.2289 8.02702 18.0931 8 17.9561 8C17.819 8 17.6832 8.02702 17.5566 8.07952C17.43 8.13203 17.3149 8.20898 17.2181 8.30597L11.9981 13.533L6.78005 8.30597C6.68327 8.20901 6.56831 8.13208 6.44176 8.07959C6.31521 8.0271 6.17956 8.00008 6.04255 8.00008C5.90555 8.00008 5.76989 8.0271 5.64334 8.07959C5.51679 8.13208 5.40184 8.20901 5.30505 8.30597H5.30605Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 943 B |
@@ -31,7 +31,7 @@ dependencies:
|
|||||||
lottie: ^1.0.1
|
lottie: ^1.0.1
|
||||||
meta: ^1.3.0
|
meta: ^1.3.0
|
||||||
path_provider: ^2.0.1
|
path_provider: ^2.0.1
|
||||||
photo_manager: ^1.1.6
|
photo_manager: ^1.2.6+1
|
||||||
photo_view: ^0.12.0
|
photo_view: ^0.12.0
|
||||||
rxdart: ^0.27.0
|
rxdart: ^0.27.0
|
||||||
scrollable_positioned_list: ^0.2.0-nullsafety.0
|
scrollable_positioned_list: ^0.2.0-nullsafety.0
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
## Upcoming
|
||||||
|
|
||||||
|
✅ Added
|
||||||
|
- Added `MessageListCore.paginationLimit`
|
||||||
|
|
||||||
## 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
🛑️ Breaking Changes from `1.5.3`
|
🛑️ Breaking Changes from `1.5.3`
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ class MessageListCore extends StatefulWidget {
|
|||||||
this.parentMessage,
|
this.parentMessage,
|
||||||
this.messageListController,
|
this.messageListController,
|
||||||
this.messageFilter,
|
this.messageFilter,
|
||||||
|
this.paginationLimit = 20,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// A [MessageListController] allows pagination.
|
/// A [MessageListController] allows pagination.
|
||||||
@@ -86,6 +87,9 @@ class MessageListCore extends StatefulWidget {
|
|||||||
/// Function used to build an empty widget
|
/// Function used to build an empty widget
|
||||||
final WidgetBuilder emptyBuilder;
|
final WidgetBuilder emptyBuilder;
|
||||||
|
|
||||||
|
/// Limit used to paginate messages
|
||||||
|
final int paginationLimit;
|
||||||
|
|
||||||
/// Callback triggered when an error occurs while performing the given
|
/// Callback triggered when an error occurs while performing the given
|
||||||
/// request.
|
/// request.
|
||||||
///
|
///
|
||||||
@@ -163,13 +167,20 @@ class MessageListCoreState extends State<MessageListCore> {
|
|||||||
/// Fetches more messages with updated pagination and updates the widget.
|
/// Fetches more messages with updated pagination and updates the widget.
|
||||||
///
|
///
|
||||||
/// Optionally pass the fetch direction, defaults to [QueryDirection.top]
|
/// Optionally pass the fetch direction, defaults to [QueryDirection.top]
|
||||||
|
/// Optionally pass a limit, defaults to 20
|
||||||
Future<void> paginateData({
|
Future<void> paginateData({
|
||||||
QueryDirection direction = QueryDirection.top,
|
QueryDirection direction = QueryDirection.top,
|
||||||
}) {
|
}) {
|
||||||
if (!_isThreadConversation) {
|
if (!_isThreadConversation) {
|
||||||
return _streamChannel!.queryMessages(direction: direction);
|
return _streamChannel!.queryMessages(
|
||||||
|
direction: direction,
|
||||||
|
limit: widget.paginationLimit,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return _streamChannel!.getReplies(widget.parentMessage!.id);
|
return _streamChannel!.getReplies(
|
||||||
|
widget.parentMessage!.id,
|
||||||
|
limit: widget.paginationLimit,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +190,10 @@ class MessageListCoreState extends State<MessageListCore> {
|
|||||||
|
|
||||||
if (newStreamChannel != _streamChannel) {
|
if (newStreamChannel != _streamChannel) {
|
||||||
if (_streamChannel == null /*only first time*/ && _isThreadConversation) {
|
if (_streamChannel == null /*only first time*/ && _isThreadConversation) {
|
||||||
newStreamChannel.getReplies(widget.parentMessage!.id);
|
newStreamChannel.getReplies(
|
||||||
|
widget.parentMessage!.id,
|
||||||
|
limit: widget.paginationLimit,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_streamChannel = newStreamChannel;
|
_streamChannel = newStreamChannel;
|
||||||
}
|
}
|
||||||
@@ -197,7 +211,10 @@ class MessageListCoreState extends State<MessageListCore> {
|
|||||||
|
|
||||||
if (widget.parentMessage?.id != widget.parentMessage?.id) {
|
if (widget.parentMessage?.id != widget.parentMessage?.id) {
|
||||||
if (_isThreadConversation) {
|
if (_isThreadConversation) {
|
||||||
_streamChannel!.getReplies(widget.parentMessage!.id);
|
_streamChannel!.getReplies(
|
||||||
|
widget.parentMessage!.id,
|
||||||
|
limit: widget.paginationLimit,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,9 +147,18 @@ class StreamChannelState extends State<StreamChannel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Calls [channel.query] updating [queryMessage] stream
|
/// Calls [channel.query] updating [queryMessage] stream
|
||||||
Future<void> queryMessages({QueryDirection? direction = QueryDirection.top}) {
|
Future<void> queryMessages({
|
||||||
if (direction == QueryDirection.top) return _queryTopMessages();
|
QueryDirection? direction = QueryDirection.top,
|
||||||
return _queryBottomMessages();
|
int limit = 20,
|
||||||
|
}) {
|
||||||
|
if (direction == QueryDirection.top) {
|
||||||
|
return _queryTopMessages(
|
||||||
|
limit: limit,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _queryBottomMessages(
|
||||||
|
limit: limit,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls [channel.getReplies] updating [queryMessage] stream
|
/// Calls [channel.getReplies] updating [queryMessage] stream
|
||||||
|
|||||||
@@ -151,7 +151,9 @@ void main() {
|
|||||||
(tester) async {
|
(tester) async {
|
||||||
const messageListCoreKey = Key('messageListCore');
|
const messageListCoreKey = Key('messageListCore');
|
||||||
final controller = MessageListController();
|
final controller = MessageListController();
|
||||||
|
const paginationLimit = 10;
|
||||||
final messageListCore = MessageListCore(
|
final messageListCore = MessageListCore(
|
||||||
|
paginationLimit: paginationLimit,
|
||||||
key: messageListCoreKey,
|
key: messageListCoreKey,
|
||||||
messageListBuilder: (_, __) => const Offstage(),
|
messageListBuilder: (_, __) => const Offstage(),
|
||||||
loadingBuilder: (BuildContext context) => const Offstage(),
|
loadingBuilder: (BuildContext context) => const Offstage(),
|
||||||
@@ -165,10 +167,6 @@ void main() {
|
|||||||
final mockChannel = MockChannel();
|
final mockChannel = MockChannel();
|
||||||
|
|
||||||
when(() => mockChannel.state.isUpToDate).thenReturn(true);
|
when(() => mockChannel.state.isUpToDate).thenReturn(true);
|
||||||
// when(() => mockChannel.query(
|
|
||||||
// messagesPagination: any(named: 'messagesPagination'),
|
|
||||||
// preferOffline: any(named: 'preferOffline'),
|
|
||||||
// )).thenAnswer((_) => mockChannel.state);
|
|
||||||
final messages = _generateMessages();
|
final messages = _generateMessages();
|
||||||
when(() => mockChannel.state.messages).thenReturn(messages);
|
when(() => mockChannel.state.messages).thenReturn(messages);
|
||||||
when(() => mockChannel.state.messagesStream)
|
when(() => mockChannel.state.messagesStream)
|
||||||
@@ -191,7 +189,10 @@ void main() {
|
|||||||
await coreState.paginateData();
|
await coreState.paginateData();
|
||||||
|
|
||||||
verify(() => mockChannel.query(
|
verify(() => mockChannel.query(
|
||||||
messagesPagination: any(named: 'messagesPagination'),
|
messagesPagination: any(
|
||||||
|
named: 'messagesPagination',
|
||||||
|
that: wrapMatcher((it) => it.limit == paginationLimit),
|
||||||
|
),
|
||||||
preferOffline: any(named: 'preferOffline'),
|
preferOffline: any(named: 'preferOffline'),
|
||||||
)).called(1);
|
)).called(1);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import 'dart:math' as math;
|
|
||||||
|
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
import 'package:stream_chat_persistence/src/dao/channel_query_dao.dart';
|
import 'package:stream_chat_persistence/src/dao/channel_query_dao.dart';
|
||||||
import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
|
import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
|
||||||
@@ -84,9 +82,9 @@ void main() {
|
|||||||
cid: cids[index],
|
cid: cids[index],
|
||||||
createdBy: users[index],
|
createdBy: users[index],
|
||||||
config: ChannelConfig(),
|
config: ChannelConfig(),
|
||||||
extraData: {'test_custom_field': math.Random().nextInt(100)},
|
extraData: {'test_custom_field': 3 + index},
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
memberCount: math.Random().nextInt(100),
|
memberCount: 3 + index,
|
||||||
lastMessageAt: now.add(Duration(hours: index)),
|
lastMessageAt: now.add(Duration(hours: index)),
|
||||||
),
|
),
|
||||||
).reversed.toList(growable: false);
|
).reversed.toList(growable: false);
|
||||||
@@ -99,6 +97,8 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group('getChannels', () {
|
group('getChannels', () {
|
||||||
|
tearDown(() async => database.flush());
|
||||||
|
|
||||||
final filter = Filter.in_('members', const ['testUserId']);
|
final filter = Filter.in_('members', const ['testUserId']);
|
||||||
|
|
||||||
test('should return empty list of channels', () async {
|
test('should return empty list of channels', () async {
|
||||||
|
|||||||
Reference in New Issue
Block a user