test: add tests for stream chat flutter (#335)
* feat: Added tests * feat: Added header test * feat: Added new tests * fix * feat: Added test, fmt * feat: Added delete test * added system and unread ind tests * fix: analysis * added new tests * fix: analysis * added tests * add attachment actions modal tests * fix analysis * fix analysis * add backbutton tests * fix analysis * increase timeout * add channelheader tests * add infotile tests * add reactions modal and channel unread indicator tests * add golden test for reaction bubble * add dark tests * add system message golden * add deletd message golden * add message action modal tests * update goldens * update workflow runner * update goldens * remove channel unread indicator in favor of unread indicator * move file and media screen to sample app * add channel image tesst * add channel_list_header test * add thread_header test * bump up test threashold * fix review Co-authored-by: Salvatore Giordano <[email protected]>
@@ -58,7 +58,7 @@ jobs:
|
|||||||
./.github/workflows/scripts/validate-formatting.sh
|
./.github/workflows/scripts/validate-formatting.sh
|
||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: macos-latest
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -102,4 +102,4 @@ jobs:
|
|||||||
- uses: VeryGoodOpenSource/[email protected]
|
- uses: VeryGoodOpenSource/[email protected]
|
||||||
with:
|
with:
|
||||||
path: packages/stream_chat_flutter/coverage/lcov.info
|
path: packages/stream_chat_flutter/coverage/lcov.info
|
||||||
min_coverage: 16
|
min_coverage: 35
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// ignore_for_file: public_member_api_docs
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:stream_chat/src/models/action.dart';
|
import 'package:stream_chat/src/models/action.dart';
|
||||||
import 'package:stream_chat/src/models/attachment_file.dart';
|
import 'package:stream_chat/src/models/attachment_file.dart';
|
||||||
@@ -10,7 +11,7 @@ part 'attachment.g.dart';
|
|||||||
|
|
||||||
/// The class that contains the information about an attachment
|
/// The class that contains the information about an attachment
|
||||||
@JsonSerializable(includeIfNull: false)
|
@JsonSerializable(includeIfNull: false)
|
||||||
class Attachment {
|
class Attachment extends Equatable {
|
||||||
/// Constructor used for json serialization
|
/// Constructor used for json serialization
|
||||||
Attachment({
|
Attachment({
|
||||||
String id,
|
String id,
|
||||||
@@ -37,12 +38,11 @@ class Attachment {
|
|||||||
UploadState uploadState,
|
UploadState uploadState,
|
||||||
}) : id = id ?? Uuid().v4(),
|
}) : id = id ?? Uuid().v4(),
|
||||||
title = title ?? file?.name,
|
title = title ?? file?.name,
|
||||||
localUri = file?.path != null ? Uri.parse(file.path) : null {
|
localUri = file?.path != null ? Uri.parse(file.path) : null,
|
||||||
this.uploadState = uploadState ??
|
uploadState = uploadState ??
|
||||||
((assetUrl != null || imageUrl != null)
|
((assetUrl != null || imageUrl != null)
|
||||||
? const UploadState.success()
|
? const UploadState.success()
|
||||||
: const UploadState.preparing());
|
: const UploadState.preparing());
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new instance from a json
|
/// Create a new instance from a json
|
||||||
factory Attachment.fromJson(Map<String, dynamic> json) =>
|
factory Attachment.fromJson(Map<String, dynamic> json) =>
|
||||||
@@ -104,7 +104,7 @@ class Attachment {
|
|||||||
final AttachmentFile file;
|
final AttachmentFile file;
|
||||||
|
|
||||||
/// The current upload state of the attachment
|
/// The current upload state of the attachment
|
||||||
UploadState uploadState;
|
final UploadState uploadState;
|
||||||
|
|
||||||
/// Map of custom channel extraData
|
/// Map of custom channel extraData
|
||||||
@JsonKey(includeIfNull: false)
|
@JsonKey(includeIfNull: false)
|
||||||
@@ -205,49 +205,28 @@ class Attachment {
|
|||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
List<Object> get props => [
|
||||||
identical(this, other) ||
|
id,
|
||||||
other is Attachment &&
|
type,
|
||||||
runtimeType == other.runtimeType &&
|
titleLink,
|
||||||
type == other.type &&
|
title,
|
||||||
titleLink == other.titleLink &&
|
thumbUrl,
|
||||||
title == other.title &&
|
text,
|
||||||
thumbUrl == other.thumbUrl &&
|
pretext,
|
||||||
text == other.text &&
|
ogScrapeUrl,
|
||||||
pretext == other.pretext &&
|
imageUrl,
|
||||||
ogScrapeUrl == other.ogScrapeUrl &&
|
footerIcon,
|
||||||
imageUrl == other.imageUrl &&
|
footer,
|
||||||
footerIcon == other.footerIcon &&
|
fields,
|
||||||
footer == other.footer &&
|
fallback,
|
||||||
fields == other.fields &&
|
color,
|
||||||
fallback == other.fallback &&
|
authorName,
|
||||||
color == other.color &&
|
authorLink,
|
||||||
authorName == other.authorName &&
|
authorIcon,
|
||||||
authorLink == other.authorLink &&
|
assetUrl,
|
||||||
authorIcon == other.authorIcon &&
|
actions,
|
||||||
assetUrl == other.assetUrl &&
|
file,
|
||||||
actions == other.actions &&
|
uploadState,
|
||||||
extraData == other.extraData;
|
extraData,
|
||||||
|
];
|
||||||
@override
|
|
||||||
int get hashCode =>
|
|
||||||
type.hashCode ^
|
|
||||||
titleLink.hashCode ^
|
|
||||||
title.hashCode ^
|
|
||||||
thumbUrl.hashCode ^
|
|
||||||
text.hashCode ^
|
|
||||||
pretext.hashCode ^
|
|
||||||
ogScrapeUrl.hashCode ^
|
|
||||||
imageUrl.hashCode ^
|
|
||||||
footerIcon.hashCode ^
|
|
||||||
footer.hashCode ^
|
|
||||||
fields.hashCode ^
|
|
||||||
fallback.hashCode ^
|
|
||||||
color.hashCode ^
|
|
||||||
authorName.hashCode ^
|
|
||||||
authorLink.hashCode ^
|
|
||||||
authorIcon.hashCode ^
|
|
||||||
assetUrl.hashCode ^
|
|
||||||
actions.hashCode ^
|
|
||||||
extraData.hashCode;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:stream_chat/src/models/attachment.dart';
|
import 'package:stream_chat/src/models/attachment.dart';
|
||||||
import 'package:stream_chat/src/models/reaction.dart';
|
import 'package:stream_chat/src/models/reaction.dart';
|
||||||
@@ -41,7 +42,7 @@ enum MessageSendingStatus {
|
|||||||
|
|
||||||
/// The class that contains the information about a message
|
/// The class that contains the information about a message
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class Message {
|
class Message extends Equatable {
|
||||||
/// Constructor used for json serialization
|
/// Constructor used for json serialization
|
||||||
Message({
|
Message({
|
||||||
String id,
|
String id,
|
||||||
@@ -345,6 +346,39 @@ class Message {
|
|||||||
pinnedBy: other.pinnedBy,
|
pinnedBy: other.pinnedBy,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [
|
||||||
|
id,
|
||||||
|
text,
|
||||||
|
type,
|
||||||
|
attachments,
|
||||||
|
mentionedUsers,
|
||||||
|
reactionCounts,
|
||||||
|
reactionScores,
|
||||||
|
latestReactions,
|
||||||
|
ownReactions,
|
||||||
|
parentId,
|
||||||
|
quotedMessage,
|
||||||
|
quotedMessageId,
|
||||||
|
replyCount,
|
||||||
|
threadParticipants,
|
||||||
|
showInChannel,
|
||||||
|
shadowed,
|
||||||
|
silent,
|
||||||
|
command,
|
||||||
|
createdAt,
|
||||||
|
updatedAt,
|
||||||
|
deletedAt,
|
||||||
|
user,
|
||||||
|
pinned,
|
||||||
|
pinnedAt,
|
||||||
|
pinExpires,
|
||||||
|
pinnedBy,
|
||||||
|
extraData,
|
||||||
|
status,
|
||||||
|
skipPush,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A translated message
|
/// A translated message
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export './src/attachment_file_uploader.dart' show AttachmentFileUploader;
|
|||||||
export './src/client.dart';
|
export './src/client.dart';
|
||||||
export './src/db/chat_persistence_client.dart';
|
export './src/db/chat_persistence_client.dart';
|
||||||
export './src/event_type.dart';
|
export './src/event_type.dart';
|
||||||
|
export './src/exceptions.dart';
|
||||||
export './src/extensions/rate_limit.dart';
|
export './src/extensions/rate_limit.dart';
|
||||||
export './src/extensions/string_extension.dart';
|
export './src/extensions/string_extension.dart';
|
||||||
export './src/models/action.dart';
|
export './src/models/action.dart';
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ dependencies:
|
|||||||
async: ^2.4.2
|
async: ^2.4.2
|
||||||
collection: ^1.14.13
|
collection: ^1.14.13
|
||||||
dio: ^3.0.10
|
dio: ^3.0.10
|
||||||
|
equatable: ^2.0.0
|
||||||
freezed_annotation: ^0.12.0
|
freezed_annotation: ^0.12.0
|
||||||
http_parser: ^3.1.4
|
http_parser: ^3.1.4
|
||||||
json_annotation: ^3.0.1
|
json_annotation: ^3.0.1
|
||||||
|
|||||||
@@ -62,4 +62,7 @@ doc/api/
|
|||||||
fvm
|
fvm
|
||||||
google-services.json
|
google-services.json
|
||||||
example/ios/dist
|
example/ios/dist
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
|
# don't check in golden failure output
|
||||||
|
**/failures/*.png
|
||||||
@@ -34,12 +34,12 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
|
|
||||||
/// Returns a new [AttachmentActionsModal]
|
/// Returns a new [AttachmentActionsModal]
|
||||||
const AttachmentActionsModal({
|
const AttachmentActionsModal({
|
||||||
|
@required this.currentIndex,
|
||||||
this.message,
|
this.message,
|
||||||
this.currentIndex,
|
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
this.imageDownloader,
|
this.imageDownloader,
|
||||||
this.fileDownloader,
|
this.fileDownloader,
|
||||||
});
|
}) : assert(currentIndex != null, 'currentIndex cannot be null');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -145,19 +145,20 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
() {
|
() {
|
||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
if (message.attachments.length > 1 ||
|
if (message.attachments.length > 1 ||
|
||||||
message.text.isNotEmpty) {
|
message.text?.isNotEmpty == true) {
|
||||||
final remainingAttachments = [...message.attachments]
|
final remainingAttachments = [...message.attachments]
|
||||||
..removeAt(currentIndex);
|
..removeAt(currentIndex);
|
||||||
channel.updateMessage(message.copyWith(
|
channel.updateMessage(message.copyWith(
|
||||||
attachments: remainingAttachments,
|
attachments: remainingAttachments,
|
||||||
));
|
));
|
||||||
Navigator.pop(context);
|
Navigator.of(context)
|
||||||
Navigator.pop(context);
|
..pop()
|
||||||
|
..maybePop();
|
||||||
} else {
|
} else {
|
||||||
channel.deleteMessage(message).then((value) {
|
channel.deleteMessage(message);
|
||||||
Navigator.pop(context);
|
Navigator.of(context)
|
||||||
Navigator.pop(context);
|
..pop()
|
||||||
});
|
..maybePop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
color: theme.colorTheme.accentRed,
|
color: theme.colorTheme.accentRed,
|
||||||
@@ -185,8 +186,10 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
StreamSvgIcon icon,
|
StreamSvgIcon icon,
|
||||||
VoidCallback onTap, {
|
VoidCallback onTap, {
|
||||||
Color color,
|
Color color,
|
||||||
|
Key key,
|
||||||
}) {
|
}) {
|
||||||
return Material(
|
return Material(
|
||||||
|
key: key,
|
||||||
color: StreamChatTheme.of(context).colorTheme.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
@@ -224,7 +227,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
if (progress == null || progress?.toProgressIndicatorValue == 1.0) {
|
if (progress == null || progress?.toProgressIndicatorValue == 1.0) {
|
||||||
Future.delayed(
|
Future.delayed(
|
||||||
const Duration(milliseconds: 500),
|
const Duration(milliseconds: 500),
|
||||||
Navigator.of(context).pop,
|
Navigator.of(context).maybePop,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Material(
|
return Material(
|
||||||
@@ -248,6 +251,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: progress.toProgressIndicatorValue == 1.0
|
: progress.toProgressIndicatorValue == 1.0
|
||||||
? Container(
|
? Container(
|
||||||
|
key: Key('completedIcon'),
|
||||||
height: 160,
|
height: 160,
|
||||||
width: 160,
|
width: 160,
|
||||||
child: StreamSvgIcon.check(
|
child: StreamSvgIcon.check(
|
||||||
|
|||||||
@@ -1,182 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
import 'attachment/attachment.dart';
|
|
||||||
|
|
||||||
class ChannelFileDisplayScreen extends StatefulWidget {
|
|
||||||
/// The sorting used for the channels matching the filters.
|
|
||||||
/// Sorting is based on field and direction, multiple sorting options can be provided.
|
|
||||||
/// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count.
|
|
||||||
/// Direction can be ascending or descending.
|
|
||||||
final List<SortOption> sortOptions;
|
|
||||||
|
|
||||||
/// Pagination parameters
|
|
||||||
/// limit: the number of users to return (max is 30)
|
|
||||||
/// offset: the offset (max is 1000)
|
|
||||||
/// message_limit: how many messages should be included to each channel
|
|
||||||
final PaginationParams paginationParams;
|
|
||||||
|
|
||||||
/// The builder used when the file list is empty.
|
|
||||||
final WidgetBuilder emptyBuilder;
|
|
||||||
|
|
||||||
const ChannelFileDisplayScreen({
|
|
||||||
this.sortOptions,
|
|
||||||
this.paginationParams,
|
|
||||||
this.emptyBuilder,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_ChannelFileDisplayScreenState createState() =>
|
|
||||||
_ChannelFileDisplayScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ChannelFileDisplayScreenState extends State<ChannelFileDisplayScreen> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
final messageSearchBloc = MessageSearchBloc.of(context);
|
|
||||||
messageSearchBloc.search(
|
|
||||||
filter: {
|
|
||||||
'cid': {
|
|
||||||
r'$in': [StreamChannel.of(context).channel.cid]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
messageFilter: {
|
|
||||||
'attachments.type': {
|
|
||||||
r'$in': ['file'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sort: widget.sortOptions,
|
|
||||||
pagination: widget.paginationParams,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
|
||||||
appBar: AppBar(
|
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
elevation: 1,
|
|
||||||
centerTitle: true,
|
|
||||||
title: Text(
|
|
||||||
'Files',
|
|
||||||
style: TextStyle(
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.black,
|
|
||||||
fontSize: 16.0),
|
|
||||||
),
|
|
||||||
leading: Center(
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 24.0,
|
|
||||||
height: 24.0,
|
|
||||||
child: StreamSvgIcon.left(
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.black,
|
|
||||||
size: 24.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
|
||||||
),
|
|
||||||
body: _buildMediaGrid(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildMediaGrid() {
|
|
||||||
final messageSearchBloc = MessageSearchBloc.of(context);
|
|
||||||
|
|
||||||
return StreamBuilder<List<GetMessageResponse>>(
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.data == null) {
|
|
||||||
return Center(
|
|
||||||
child: const CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snapshot.data.isEmpty) {
|
|
||||||
if (widget.emptyBuilder != null) {
|
|
||||||
return widget.emptyBuilder(context);
|
|
||||||
}
|
|
||||||
return Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
StreamSvgIcon.files(
|
|
||||||
size: 136.0,
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
|
||||||
),
|
|
||||||
SizedBox(height: 16.0),
|
|
||||||
Text(
|
|
||||||
'No Files',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.0,
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.black,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 8.0),
|
|
||||||
Text(
|
|
||||||
'Files sent in this chat will appear here',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.0,
|
|
||||||
color: StreamChatTheme.of(context)
|
|
||||||
.colorTheme
|
|
||||||
.black
|
|
||||||
.withOpacity(0.5),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final media = <Attachment, Message>{};
|
|
||||||
|
|
||||||
for (var item in snapshot.data) {
|
|
||||||
item.message.attachments.where((e) => e.type == 'file').forEach((e) {
|
|
||||||
media[e] = item.message;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return LazyLoadScrollView(
|
|
||||||
onEndOfPage: () => messageSearchBloc.search(
|
|
||||||
filter: {
|
|
||||||
'cid': {
|
|
||||||
r'$in': [StreamChannel.of(context).channel.cid]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
messageFilter: {
|
|
||||||
'attachments.type': {
|
|
||||||
r'$in': ['file']
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sort: widget.sortOptions,
|
|
||||||
pagination: widget.paginationParams.copyWith(
|
|
||||||
offset: messageSearchBloc.messageResponses?.length ?? 0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: ListView.builder(
|
|
||||||
itemBuilder: (context, position) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(1.0),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: FileAttachment(
|
|
||||||
message: media.values.toList()[position],
|
|
||||||
attachment: media.keys.toList()[position],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
itemCount: media.length,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
stream: messageSearchBloc.messagesStream,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -50,7 +50,6 @@ class ChannelImage extends StatelessWidget {
|
|||||||
this.channel,
|
this.channel,
|
||||||
this.constraints,
|
this.constraints,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.showOnlineStatus = true,
|
|
||||||
this.borderRadius,
|
this.borderRadius,
|
||||||
this.selected = false,
|
this.selected = false,
|
||||||
this.selectionColor,
|
this.selectionColor,
|
||||||
@@ -68,8 +67,6 @@ class ChannelImage extends StatelessWidget {
|
|||||||
/// The function called when the image is tapped
|
/// The function called when the image is tapped
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
|
|
||||||
final bool showOnlineStatus;
|
|
||||||
|
|
||||||
final bool selected;
|
final bool selected;
|
||||||
|
|
||||||
final Color selectionColor;
|
final Color selectionColor;
|
||||||
@@ -81,142 +78,144 @@ class ChannelImage extends StatelessWidget {
|
|||||||
final streamChat = StreamChat.of(context);
|
final streamChat = StreamChat.of(context);
|
||||||
final channel = this.channel ?? StreamChannel.of(context).channel;
|
final channel = this.channel ?? StreamChannel.of(context).channel;
|
||||||
return StreamBuilder<Map<String, dynamic>>(
|
return StreamBuilder<Map<String, dynamic>>(
|
||||||
stream: channel.extraDataStream,
|
stream: channel.extraDataStream,
|
||||||
initialData: channel.extraData,
|
initialData: channel.extraData,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
String image;
|
String image;
|
||||||
if (snapshot.data?.containsKey('image') == true) {
|
if (snapshot.data?.containsKey('image') == true) {
|
||||||
image = snapshot.data['image'];
|
image = snapshot.data['image'];
|
||||||
} else if (channel.state.members?.length == 2) {
|
} else if (channel.state.members?.length == 2) {
|
||||||
final otherMember = channel.state.members
|
final otherMember = channel.state.members
|
||||||
.firstWhere((member) => member.user.id != streamChat.user.id);
|
.firstWhere((member) => member.user.id != streamChat.user.id);
|
||||||
return StreamBuilder<User>(
|
return StreamBuilder<User>(
|
||||||
stream: streamChat.client.state.usersStream
|
stream: streamChat.client.state.usersStream
|
||||||
.map((users) => users[otherMember.userId]),
|
.map((users) => users[otherMember.userId]),
|
||||||
initialData: otherMember.user,
|
initialData: otherMember.user,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
return UserAvatar(
|
return UserAvatar(
|
||||||
borderRadius: borderRadius ??
|
borderRadius: borderRadius ??
|
||||||
StreamChatTheme.of(context)
|
StreamChatTheme.of(context)
|
||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
.avatarTheme
|
.avatarTheme
|
||||||
.borderRadius,
|
.borderRadius,
|
||||||
user: snapshot.data ?? otherMember.user,
|
user: snapshot.data ?? otherMember.user,
|
||||||
constraints: constraints ??
|
constraints: constraints ??
|
||||||
StreamChatTheme.of(context)
|
StreamChatTheme.of(context)
|
||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
.avatarTheme
|
.avatarTheme
|
||||||
.constraints,
|
.constraints,
|
||||||
onTap: onTap != null ? (_) => onTap() : null,
|
onTap: onTap != null ? (_) => onTap() : null,
|
||||||
selected: selected,
|
selected: selected,
|
||||||
selectionColor: selectionColor ??
|
selectionColor: selectionColor ??
|
||||||
StreamChatTheme.of(context).colorTheme.accentBlue,
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
selectionThickness: selectionThickness,
|
selectionThickness: selectionThickness,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
final images = channel.state.members
|
final images = channel.state.members
|
||||||
.where((member) =>
|
.where((member) =>
|
||||||
member.user.id != streamChat.user.id &&
|
member.user.id != streamChat.user.id &&
|
||||||
member.user.extraData['image'] != null)
|
member.user.extraData['image'] != null)
|
||||||
.take(4)
|
.take(4)
|
||||||
.map((e) => e.user.extraData['image'] as String)
|
.map((e) => e.user.extraData['image'] as String)
|
||||||
.toList();
|
.toList();
|
||||||
return GroupImage(
|
return GroupImage(
|
||||||
images: images,
|
images: images,
|
||||||
borderRadius: borderRadius ??
|
|
||||||
StreamChatTheme.of(context)
|
|
||||||
.channelPreviewTheme
|
|
||||||
.avatarTheme
|
|
||||||
.borderRadius,
|
|
||||||
constraints: constraints ??
|
|
||||||
StreamChatTheme.of(context)
|
|
||||||
.channelPreviewTheme
|
|
||||||
.avatarTheme
|
|
||||||
.constraints,
|
|
||||||
onTap: onTap,
|
|
||||||
selected: selected,
|
|
||||||
selectionColor: selectionColor ??
|
|
||||||
StreamChatTheme.of(context).colorTheme.accentBlue,
|
|
||||||
selectionThickness: selectionThickness,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget child = ClipRRect(
|
|
||||||
borderRadius: borderRadius ??
|
borderRadius: borderRadius ??
|
||||||
StreamChatTheme.of(context)
|
StreamChatTheme.of(context)
|
||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
.avatarTheme
|
.avatarTheme
|
||||||
.borderRadius,
|
.borderRadius,
|
||||||
child: Container(
|
constraints: constraints ??
|
||||||
constraints: constraints ??
|
StreamChatTheme.of(context)
|
||||||
StreamChatTheme.of(context)
|
.channelPreviewTheme
|
||||||
.channelPreviewTheme
|
.avatarTheme
|
||||||
.avatarTheme
|
.constraints,
|
||||||
.constraints,
|
onTap: onTap,
|
||||||
decoration: BoxDecoration(
|
selected: selected,
|
||||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
selectionColor: selectionColor ??
|
||||||
),
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
child: Stack(
|
selectionThickness: selectionThickness,
|
||||||
alignment: Alignment.center,
|
|
||||||
fit: StackFit.expand,
|
|
||||||
children: <Widget>[
|
|
||||||
image != null
|
|
||||||
? CachedNetworkImage(
|
|
||||||
imageUrl: image,
|
|
||||||
errorWidget: (_, __, ___) {
|
|
||||||
return Center(
|
|
||||||
child: Text(
|
|
||||||
snapshot.data?.containsKey('name') ?? false
|
|
||||||
? snapshot.data['name'][0]
|
|
||||||
: '',
|
|
||||||
style: TextStyle(
|
|
||||||
color: StreamChatTheme.of(context)
|
|
||||||
.colorTheme
|
|
||||||
.white,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
)
|
|
||||||
: StreamChatTheme.of(context)
|
|
||||||
.defaultChannelImage(context, channel),
|
|
||||||
Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: onTap,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
if (selected) {
|
}
|
||||||
child = ClipRRect(
|
|
||||||
borderRadius: (borderRadius ??
|
Widget child = ClipRRect(
|
||||||
StreamChatTheme.of(context)
|
borderRadius: borderRadius ??
|
||||||
.ownMessageTheme
|
StreamChatTheme.of(context)
|
||||||
.avatarTheme
|
.channelPreviewTheme
|
||||||
.borderRadius) +
|
.avatarTheme
|
||||||
BorderRadius.circular(selectionThickness),
|
.borderRadius,
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: constraints ??
|
constraints: constraints ??
|
||||||
|
StreamChatTheme.of(context)
|
||||||
|
.channelPreviewTheme
|
||||||
|
.avatarTheme
|
||||||
|
.constraints,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
|
),
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
fit: StackFit.expand,
|
||||||
|
children: <Widget>[
|
||||||
|
image != null
|
||||||
|
? CachedNetworkImage(
|
||||||
|
imageUrl: image,
|
||||||
|
errorWidget: (_, __, ___) {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
snapshot.data?.containsKey('name') ?? false
|
||||||
|
? snapshot.data['name'][0]
|
||||||
|
: '',
|
||||||
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
)
|
||||||
|
: StreamChatTheme.of(context)
|
||||||
|
.defaultChannelImage(context, channel),
|
||||||
|
Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (selected) {
|
||||||
|
child = ClipRRect(
|
||||||
|
key: Key('selectedImage'),
|
||||||
|
borderRadius: (borderRadius ??
|
||||||
StreamChatTheme.of(context)
|
StreamChatTheme.of(context)
|
||||||
.ownMessageTheme
|
.ownMessageTheme
|
||||||
.avatarTheme
|
.avatarTheme
|
||||||
.constraints,
|
.borderRadius) +
|
||||||
color: selectionColor ??
|
BorderRadius.circular(selectionThickness),
|
||||||
StreamChatTheme.of(context).colorTheme.accentBlue,
|
child: Container(
|
||||||
child: Padding(
|
constraints: constraints ??
|
||||||
padding: EdgeInsets.all(selectionThickness),
|
StreamChatTheme.of(context)
|
||||||
child: child,
|
.ownMessageTheme
|
||||||
),
|
.avatarTheme
|
||||||
|
.constraints,
|
||||||
|
color: selectionColor ??
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(selectionThickness),
|
||||||
|
child: child,
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
}
|
);
|
||||||
return child;
|
}
|
||||||
});
|
return child;
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,251 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
import 'package:video_player/video_player.dart';
|
|
||||||
|
|
||||||
import 'attachment/attachment.dart';
|
|
||||||
|
|
||||||
class ChannelMediaDisplayScreen extends StatefulWidget {
|
|
||||||
/// The sorting used for the channels matching the filters.
|
|
||||||
/// Sorting is based on field and direction, multiple sorting options can be provided.
|
|
||||||
/// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count.
|
|
||||||
/// Direction can be ascending or descending.
|
|
||||||
final List<SortOption> sortOptions;
|
|
||||||
|
|
||||||
/// Pagination parameters
|
|
||||||
/// limit: the number of users to return (max is 30)
|
|
||||||
/// offset: the offset (max is 1000)
|
|
||||||
/// message_limit: how many messages should be included to each channel
|
|
||||||
final PaginationParams paginationParams;
|
|
||||||
|
|
||||||
/// The builder used when the file list is empty.
|
|
||||||
final WidgetBuilder emptyBuilder;
|
|
||||||
|
|
||||||
final ShowMessageCallback onShowMessage;
|
|
||||||
|
|
||||||
const ChannelMediaDisplayScreen({
|
|
||||||
this.sortOptions,
|
|
||||||
this.paginationParams,
|
|
||||||
this.emptyBuilder,
|
|
||||||
this.onShowMessage,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_ChannelMediaDisplayScreenState createState() =>
|
|
||||||
_ChannelMediaDisplayScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ChannelMediaDisplayScreenState extends State<ChannelMediaDisplayScreen> {
|
|
||||||
Map<String, VideoPlayerController> controllerCache = {};
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
final messageSearchBloc = MessageSearchBloc.of(context);
|
|
||||||
messageSearchBloc.search(
|
|
||||||
filter: {
|
|
||||||
'cid': {
|
|
||||||
r'$in': [StreamChannel.of(context).channel.cid],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
messageFilter: {
|
|
||||||
'attachments.type': {
|
|
||||||
r'$in': ['image', 'video']
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sort: widget.sortOptions,
|
|
||||||
pagination: widget.paginationParams,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
|
||||||
appBar: AppBar(
|
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
elevation: 1,
|
|
||||||
centerTitle: true,
|
|
||||||
title: Text(
|
|
||||||
'Photos & Videos',
|
|
||||||
style: TextStyle(
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.black,
|
|
||||||
fontSize: 16.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
leading: Center(
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 24.0,
|
|
||||||
height: 24.0,
|
|
||||||
child: StreamSvgIcon.left(
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.black,
|
|
||||||
size: 24.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
|
||||||
),
|
|
||||||
body: _buildMediaGrid(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildMediaGrid() {
|
|
||||||
final messageSearchBloc = MessageSearchBloc.of(context);
|
|
||||||
|
|
||||||
return StreamBuilder<List<GetMessageResponse>>(
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.data == null) {
|
|
||||||
return Center(
|
|
||||||
child: const CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snapshot.data.isEmpty) {
|
|
||||||
if (widget.emptyBuilder != null) {
|
|
||||||
return widget.emptyBuilder(context);
|
|
||||||
}
|
|
||||||
return Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
StreamSvgIcon.pictures(
|
|
||||||
size: 136.0,
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
|
||||||
),
|
|
||||||
SizedBox(height: 16.0),
|
|
||||||
Text(
|
|
||||||
'No Media',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.0,
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.black,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 8.0),
|
|
||||||
Text(
|
|
||||||
'Photos or video sent in this chat will \nappear here',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.0,
|
|
||||||
color: StreamChatTheme.of(context)
|
|
||||||
.colorTheme
|
|
||||||
.black
|
|
||||||
.withOpacity(0.5),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final media = <_AssetPackage>[];
|
|
||||||
|
|
||||||
for (var item in snapshot.data) {
|
|
||||||
item.message.attachments
|
|
||||||
.where((e) =>
|
|
||||||
(e.type == 'image' || e.type == 'video') &&
|
|
||||||
e.ogScrapeUrl == null)
|
|
||||||
.forEach((e) {
|
|
||||||
VideoPlayerController controller;
|
|
||||||
if (e.type == 'video') {
|
|
||||||
var cachedController = controllerCache[e.assetUrl];
|
|
||||||
|
|
||||||
if (cachedController == null) {
|
|
||||||
controller = VideoPlayerController.network(e.assetUrl);
|
|
||||||
controller.initialize();
|
|
||||||
controllerCache[e.assetUrl] = controller;
|
|
||||||
} else {
|
|
||||||
controller = cachedController;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
media.add(_AssetPackage(e, item.message, controller));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return LazyLoadScrollView(
|
|
||||||
onEndOfPage: () => messageSearchBloc.search(
|
|
||||||
filter: {
|
|
||||||
'cid': {
|
|
||||||
r'$in': [StreamChannel.of(context).channel.cid]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
messageFilter: {
|
|
||||||
'attachments.type': {
|
|
||||||
r'$in': ['image', 'video']
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sort: widget.sortOptions,
|
|
||||||
pagination: widget.paginationParams.copyWith(
|
|
||||||
offset: messageSearchBloc.messageResponses?.length ?? 0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: GridView.builder(
|
|
||||||
gridDelegate:
|
|
||||||
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
|
|
||||||
itemBuilder: (context, position) {
|
|
||||||
var channel = StreamChannel.of(context).channel;
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(1.0),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => StreamChannel(
|
|
||||||
channel: channel,
|
|
||||||
child: FullScreenMedia(
|
|
||||||
mediaAttachments:
|
|
||||||
media.map((e) => e.attachment).toList(),
|
|
||||||
startIndex: position,
|
|
||||||
message: media[position].message,
|
|
||||||
sentAt: media[position].message.createdAt,
|
|
||||||
userName: media[position].message.user.name,
|
|
||||||
onShowMessage: widget.onShowMessage,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: media[position].attachment.type == 'image'
|
|
||||||
? IgnorePointer(
|
|
||||||
child: ImageAttachment(
|
|
||||||
attachment: media[position].attachment,
|
|
||||||
message: media[position].message,
|
|
||||||
showTitle: false,
|
|
||||||
size: Size(
|
|
||||||
MediaQuery.of(context).size.width * 0.8,
|
|
||||||
MediaQuery.of(context).size.height * 0.3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: VideoPlayer(media[position].videoPlayer),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
itemCount: media.length,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
stream: messageSearchBloc.messagesStream,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
for (var c in controllerCache.values) {
|
|
||||||
c.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AssetPackage {
|
|
||||||
Attachment attachment;
|
|
||||||
Message message;
|
|
||||||
VideoPlayerController videoPlayer;
|
|
||||||
|
|
||||||
_AssetPackage(this.attachment, this.message, this.videoPlayer);
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
|||||||
|
|
||||||
import '../stream_chat_flutter.dart';
|
import '../stream_chat_flutter.dart';
|
||||||
import 'channel_name.dart';
|
import 'channel_name.dart';
|
||||||
import 'channel_unread_indicator.dart';
|
|
||||||
|
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
@@ -98,19 +97,20 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
StreamBuilder<List<Member>>(
|
StreamBuilder<List<Member>>(
|
||||||
stream: channel.state.membersStream,
|
stream: channel.state.membersStream,
|
||||||
initialData: channel.state.members,
|
initialData: channel.state.members,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (!snapshot.hasData ||
|
if (!snapshot.hasData ||
|
||||||
snapshot.data.isEmpty ||
|
snapshot.data.isEmpty ||
|
||||||
!snapshot.data.any((Member e) =>
|
!snapshot.data.any((Member e) =>
|
||||||
e.user.id == channel.client.state.user.id)) {
|
e.user.id == channel.client.state.user.id)) {
|
||||||
return SizedBox();
|
return SizedBox();
|
||||||
}
|
}
|
||||||
return ChannelUnreadIndicator(
|
return UnreadIndicator(
|
||||||
channel: channel,
|
cid: channel.cid,
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
subtitle: Row(
|
subtitle: Row(
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
|
||||||
|
|
||||||
class ChannelUnreadIndicator extends StatelessWidget {
|
|
||||||
const ChannelUnreadIndicator({
|
|
||||||
Key key,
|
|
||||||
@required this.channel,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final Channel channel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return StreamBuilder<int>(
|
|
||||||
stream: channel.state.unreadCountStream,
|
|
||||||
initialData: channel.state.unreadCount,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (!snapshot.hasData || snapshot.data == 0) {
|
|
||||||
return SizedBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Material(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
color: StreamChatTheme.of(context)
|
|
||||||
.channelPreviewTheme
|
|
||||||
.unreadCounterColor,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 5.0,
|
|
||||||
right: 5.0,
|
|
||||||
top: 2,
|
|
||||||
bottom: 1,
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
'${snapshot.data > 99 ? '99+' : snapshot.data}',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 11,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,14 +11,15 @@ class InfoTile extends StatelessWidget {
|
|||||||
final TextStyle textStyle;
|
final TextStyle textStyle;
|
||||||
final Color backgroundColor;
|
final Color backgroundColor;
|
||||||
|
|
||||||
InfoTile(
|
InfoTile({
|
||||||
{this.message,
|
this.message,
|
||||||
this.child,
|
this.child,
|
||||||
this.showMessage,
|
this.showMessage,
|
||||||
this.tileAnchor,
|
this.tileAnchor,
|
||||||
this.childAnchor,
|
this.childAnchor,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
this.backgroundColor});
|
this.backgroundColor,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'dart:ui';
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/message_action.dart';
|
import 'package:stream_chat_flutter/src/message_action.dart';
|
||||||
import 'package:stream_chat_flutter/src/reaction_picker.dart';
|
import 'package:stream_chat_flutter/src/reaction_picker.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||||
@@ -18,11 +17,12 @@ import 'stream_chat_theme.dart';
|
|||||||
|
|
||||||
class MessageActionsModal extends StatefulWidget {
|
class MessageActionsModal extends StatefulWidget {
|
||||||
final Widget Function(BuildContext, Message) editMessageInputBuilder;
|
final Widget Function(BuildContext, Message) editMessageInputBuilder;
|
||||||
final void Function(Message) onThreadReplyTap;
|
final OnMessageTap onThreadReplyTap;
|
||||||
final void Function(Message) onReplyTap;
|
final OnMessageTap onReplyTap;
|
||||||
final Message message;
|
final Message message;
|
||||||
final MessageTheme messageTheme;
|
final MessageTheme messageTheme;
|
||||||
final bool showReactions;
|
final bool showReactions;
|
||||||
|
final OnMessageTap onCopyTap;
|
||||||
final bool showDeleteMessage;
|
final bool showDeleteMessage;
|
||||||
final bool showCopyMessage;
|
final bool showCopyMessage;
|
||||||
final bool showEditMessage;
|
final bool showEditMessage;
|
||||||
@@ -60,6 +60,7 @@ class MessageActionsModal extends StatefulWidget {
|
|||||||
this.reverse = false,
|
this.reverse = false,
|
||||||
this.customActions = const [],
|
this.customActions = const [],
|
||||||
this.attachmentBorderRadiusGeometry,
|
this.attachmentBorderRadiusGeometry,
|
||||||
|
this.onCopyTap,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -211,10 +212,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
CrossAxisAlignment.stretch,
|
CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
if (widget.showReplyMessage &&
|
if (widget.showReplyMessage &&
|
||||||
(widget.message.status ==
|
widget.message.status ==
|
||||||
MessageSendingStatus.sent ||
|
MessageSendingStatus.sent ||
|
||||||
widget.message.status == null) &&
|
widget.message.status == null)
|
||||||
widget.message.parentId == null)
|
|
||||||
_buildReplyButton(context),
|
_buildReplyButton(context),
|
||||||
if (widget.showThreadReplyMessage &&
|
if (widget.showThreadReplyMessage &&
|
||||||
(widget.message.status ==
|
(widget.message.status ==
|
||||||
@@ -452,7 +452,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
Widget _buildCopyButton(BuildContext context) {
|
Widget _buildCopyButton(BuildContext context) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await Clipboard.setData(ClipboardData(text: widget.message.text));
|
widget.onCopyTap?.call(widget.message);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|||||||
@@ -693,7 +693,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
if (!mounted) {
|
if (!mounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StreamChannel.of(context).channel.keyStroke().catchError((e) {});
|
StreamChannel.of(context).channel.keyStroke()?.catchError((e) {});
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_messageIsPresent = s.trim().isNotEmpty;
|
_messageIsPresent = s.trim().isNotEmpty;
|
||||||
@@ -2181,10 +2181,12 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
void _parseExistingMessage(Message message) {
|
void _parseExistingMessage(Message message) {
|
||||||
textEditingController.text = message.text;
|
textEditingController.text = message.text;
|
||||||
_messageIsPresent = true;
|
_messageIsPresent = true;
|
||||||
for (final attachment in message?.attachments) {
|
if (message.attachments != null) {
|
||||||
_attachments[attachment.id] = attachment.copyWith(
|
for (final attachment in message.attachments) {
|
||||||
uploadState: attachment.uploadState ?? UploadState.success(),
|
_attachments[attachment.id] = attachment.copyWith(
|
||||||
);
|
uploadState: attachment.uploadState ?? UploadState.success(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ import 'message_widget.dart';
|
|||||||
import 'stream_chat_theme.dart';
|
import 'stream_chat_theme.dart';
|
||||||
|
|
||||||
class MessageReactionsModal extends StatelessWidget {
|
class MessageReactionsModal extends StatelessWidget {
|
||||||
final Widget Function(BuildContext, Message) editMessageInputBuilder;
|
|
||||||
final void Function(Message) onThreadTap;
|
|
||||||
final Message message;
|
final Message message;
|
||||||
final MessageTheme messageTheme;
|
final MessageTheme messageTheme;
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
@@ -30,8 +28,6 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
@required this.message,
|
@required this.message,
|
||||||
@required this.messageTheme,
|
@required this.messageTheme,
|
||||||
this.showReactions = true,
|
this.showReactions = true,
|
||||||
this.onThreadTap,
|
|
||||||
this.editMessageInputBuilder,
|
|
||||||
this.messageShape,
|
this.messageShape,
|
||||||
this.attachmentShape,
|
this.attachmentShape,
|
||||||
this.reverse = false,
|
this.reverse = false,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_portal/flutter_portal.dart';
|
import 'package:flutter_portal/flutter_portal.dart';
|
||||||
import 'package:jiffy/jiffy.dart';
|
import 'package:jiffy/jiffy.dart';
|
||||||
import 'package:stream_chat_flutter/src/message_action.dart';
|
import 'package:stream_chat_flutter/src/message_action.dart';
|
||||||
@@ -841,6 +842,8 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
return StreamChannel(
|
return StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: MessageActionsModal(
|
child: MessageActionsModal(
|
||||||
|
onCopyTap: (message) =>
|
||||||
|
Clipboard.setData(ClipboardData(text: message.text)),
|
||||||
attachmentBorderRadiusGeometry:
|
attachmentBorderRadiusGeometry:
|
||||||
widget.attachmentBorderRadiusGeometry,
|
widget.attachmentBorderRadiusGeometry,
|
||||||
showUserAvatar:
|
showUserAvatar:
|
||||||
@@ -903,8 +906,6 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
widget.attachmentShape ?? _getDefaultAttachmentShape(context),
|
widget.attachmentShape ?? _getDefaultAttachmentShape(context),
|
||||||
reverse: widget.reverse,
|
reverse: widget.reverse,
|
||||||
message: widget.message,
|
message: widget.message,
|
||||||
editMessageInputBuilder: widget.editMessageInputBuilder,
|
|
||||||
onThreadTap: widget.onThreadTap,
|
|
||||||
showReactions: widget.showReactions,
|
showReactions: widget.showReactions,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:math';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:stream_chat_flutter/src/reaction_icon.dart';
|
import 'package:stream_chat_flutter/src/reaction_icon.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
@@ -36,67 +37,70 @@ class ReactionBubble extends StatelessWidget {
|
|||||||
return Transform(
|
return Transform(
|
||||||
transform: Matrix4.rotationY(reverse ? pi : 0),
|
transform: Matrix4.rotationY(reverse ? pi : 0),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Stack(
|
child: Center(
|
||||||
alignment: Alignment.center,
|
child: Stack(
|
||||||
children: [
|
alignment: Alignment.center,
|
||||||
Transform.translate(
|
fit: StackFit.loose,
|
||||||
offset: Offset(reverse ? offset : -offset, 0),
|
children: [
|
||||||
child: Container(
|
Transform.translate(
|
||||||
padding: const EdgeInsets.all(2),
|
offset: Offset(reverse ? offset : -offset, 0),
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: maskColor,
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
|
||||||
),
|
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.all(2),
|
||||||
vertical: 4,
|
|
||||||
horizontal: totalReactions > 1 ? 4 : 0,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
color: maskColor,
|
||||||
color: borderColor,
|
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||||
),
|
|
||||||
color: backgroundColor,
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
|
||||||
),
|
),
|
||||||
child: LayoutBuilder(
|
child: Container(
|
||||||
builder: (context, constraints) {
|
padding: EdgeInsets.symmetric(
|
||||||
return Flex(
|
vertical: 4,
|
||||||
direction: Axis.horizontal,
|
horizontal: totalReactions > 1 ? 4 : 0,
|
||||||
mainAxisSize: MainAxisSize.min,
|
),
|
||||||
children: [
|
decoration: BoxDecoration(
|
||||||
if (constraints.maxWidth < double.infinity)
|
border: Border.all(
|
||||||
...reactions
|
color: borderColor,
|
||||||
.take((constraints.maxWidth) ~/ 24)
|
),
|
||||||
.map((reaction) {
|
color: backgroundColor,
|
||||||
return _buildReaction(
|
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||||
reactionIcons,
|
),
|
||||||
reaction,
|
child: LayoutBuilder(
|
||||||
context,
|
builder: (context, constraints) {
|
||||||
);
|
return Flex(
|
||||||
}).toList(),
|
direction: Axis.horizontal,
|
||||||
if (constraints.maxWidth == double.infinity)
|
mainAxisSize: MainAxisSize.min,
|
||||||
...reactions.map((reaction) {
|
children: [
|
||||||
return _buildReaction(
|
if (constraints.maxWidth < double.infinity)
|
||||||
reactionIcons,
|
...reactions
|
||||||
reaction,
|
.take((constraints.maxWidth) ~/ 24)
|
||||||
context,
|
.map((reaction) {
|
||||||
);
|
return _buildReaction(
|
||||||
}).toList(),
|
reactionIcons,
|
||||||
],
|
reaction,
|
||||||
);
|
context,
|
||||||
},
|
);
|
||||||
|
}).toList(),
|
||||||
|
if (constraints.maxWidth == double.infinity)
|
||||||
|
...reactions.map((reaction) {
|
||||||
|
return _buildReaction(
|
||||||
|
reactionIcons,
|
||||||
|
reaction,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Positioned(
|
||||||
Positioned(
|
bottom: 2,
|
||||||
bottom: 2,
|
left: reverse ? null : 13,
|
||||||
left: reverse ? null : 13,
|
right: !reverse ? null : 13,
|
||||||
right: !reverse ? null : 13,
|
child: _buildReactionsTail(context),
|
||||||
child: _buildReactionsTail(context),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class UnreadIndicator extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'${snapshot.data}',
|
'${snapshot.data > 99 ? '99+' : snapshot.data}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
export 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
|
export 'src/attachment/attachment.dart';
|
||||||
export 'src/back_button.dart';
|
export 'src/back_button.dart';
|
||||||
export 'src/channel_header.dart';
|
export 'src/channel_header.dart';
|
||||||
export 'src/channel_image.dart';
|
export 'src/channel_image.dart';
|
||||||
@@ -5,39 +8,35 @@ export 'src/channel_list_header.dart';
|
|||||||
export 'src/channel_list_view.dart';
|
export 'src/channel_list_view.dart';
|
||||||
export 'src/channel_name.dart';
|
export 'src/channel_name.dart';
|
||||||
export 'src/channel_preview.dart';
|
export 'src/channel_preview.dart';
|
||||||
|
export 'src/connection_status_builder.dart';
|
||||||
export 'src/date_divider.dart';
|
export 'src/date_divider.dart';
|
||||||
export 'src/deleted_message.dart';
|
export 'src/deleted_message.dart';
|
||||||
export 'src/message_action.dart';
|
|
||||||
export 'src/attachment/attachment.dart';
|
|
||||||
export 'src/full_screen_media.dart';
|
export 'src/full_screen_media.dart';
|
||||||
export 'src/image_header.dart';
|
|
||||||
export 'src/image_footer.dart';
|
export 'src/image_footer.dart';
|
||||||
|
export 'src/image_header.dart';
|
||||||
|
export 'src/info_tile.dart';
|
||||||
|
export 'src/mention_tile.dart';
|
||||||
|
export 'src/message_action.dart';
|
||||||
export 'src/message_input.dart';
|
export 'src/message_input.dart';
|
||||||
export 'src/message_list_view.dart';
|
export 'src/message_list_view.dart';
|
||||||
|
export 'src/message_search_item.dart';
|
||||||
|
export 'src/message_search_list_view.dart';
|
||||||
export 'src/message_text.dart';
|
export 'src/message_text.dart';
|
||||||
export 'src/message_widget.dart';
|
export 'src/message_widget.dart';
|
||||||
|
export 'src/option_list_tile.dart';
|
||||||
export 'src/reaction_picker.dart';
|
export 'src/reaction_picker.dart';
|
||||||
export 'src/sending_indicator.dart';
|
export 'src/sending_indicator.dart';
|
||||||
|
export 'src/stream_chat.dart';
|
||||||
export 'src/stream_chat_theme.dart';
|
export 'src/stream_chat_theme.dart';
|
||||||
export 'src/stream_neumorphic_button.dart';
|
export 'src/stream_neumorphic_button.dart';
|
||||||
export 'src/stream_svg_icon.dart';
|
export 'src/stream_svg_icon.dart';
|
||||||
export 'src/system_message.dart';
|
export 'src/system_message.dart';
|
||||||
export 'src/thread_header.dart';
|
export 'src/thread_header.dart';
|
||||||
export 'src/typing_indicator.dart';
|
export 'src/typing_indicator.dart';
|
||||||
|
export 'src/unread_indicator.dart';
|
||||||
export 'src/user_avatar.dart';
|
export 'src/user_avatar.dart';
|
||||||
export 'src/user_item.dart';
|
export 'src/user_item.dart';
|
||||||
export 'src/user_item.dart';
|
export 'src/user_item.dart';
|
||||||
export 'src/user_list_view.dart';
|
export 'src/user_list_view.dart';
|
||||||
export 'src/user_list_view.dart';
|
export 'src/user_list_view.dart';
|
||||||
export 'src/utils.dart';
|
export 'src/utils.dart';
|
||||||
export 'src/message_search_item.dart';
|
|
||||||
export 'src/message_search_list_view.dart';
|
|
||||||
export 'src/unread_indicator.dart';
|
|
||||||
export 'src/option_list_tile.dart';
|
|
||||||
export 'src/channel_file_display_screen.dart';
|
|
||||||
export 'src/channel_media_display_screen.dart';
|
|
||||||
export 'src/info_tile.dart';
|
|
||||||
export 'src/stream_chat.dart';
|
|
||||||
export 'src/connection_status_builder.dart';
|
|
||||||
export 'src/mention_tile.dart';
|
|
||||||
export 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
|
||||||
|
|||||||
@@ -55,9 +55,12 @@ flutter:
|
|||||||
- svgs/
|
- svgs/
|
||||||
- lib/svgs/
|
- lib/svgs/
|
||||||
- animations/
|
- animations/
|
||||||
|
uses-material-design: true
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
mockito: ^4.1.3
|
mockito: ^4.1.3
|
||||||
pedantic: ^1.9.2
|
pedantic: ^1.9.2
|
||||||
|
golden_toolkit: ^0.6.0
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:golden_toolkit/golden_toolkit.dart';
|
||||||
|
|
||||||
|
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
|
||||||
|
await loadAppFonts();
|
||||||
|
return testMain();
|
||||||
|
}
|
||||||
@@ -0,0 +1,510 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/attachment_actions_modal.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
class MockAttachmentDownloader extends Mock {
|
||||||
|
ProgressCallback progressCallback;
|
||||||
|
Completer<String> completer = Completer();
|
||||||
|
|
||||||
|
Future<String> call(
|
||||||
|
Attachment attachment, {
|
||||||
|
ProgressCallback progressCallback,
|
||||||
|
}) {
|
||||||
|
this.progressCallback = progressCallback;
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show all the actions',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'text.jpg',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(find.text('Reply'), findsOneWidget);
|
||||||
|
expect(find.text('Show in Chat'), findsOneWidget);
|
||||||
|
expect(find.text('Save Image'), findsOneWidget);
|
||||||
|
expect(find.text('Delete'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should hide delete if it\'s not my message',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id2'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'text.jpg',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(find.text('Reply'), findsOneWidget);
|
||||||
|
expect(find.text('Show in Chat'), findsOneWidget);
|
||||||
|
expect(find.text('Save Image'), findsOneWidget);
|
||||||
|
expect(find.text('Delete'), findsNothing);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show save video for videos',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: Container(
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'video',
|
||||||
|
title: 'video.mp4',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(find.text('Save Video'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on reply should pop',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
final mockObserver = MockNavigatorObserver();
|
||||||
|
|
||||||
|
final message = Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'image.jpg',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
navigatorObservers: [mockObserver],
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: Container(
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
message: message,
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.tap(find.text('Reply'));
|
||||||
|
verify(mockObserver.didPop(any, any));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on show in chat should call onShowMessage',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
final onShowMessage = MockVoidCallback();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: Container(
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
onShowMessage: onShowMessage,
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'image.jpg',
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.tap(find.text('Show in Chat'));
|
||||||
|
verify(onShowMessage.call()).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on delete in chat should remove the attachment',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final mockChannel = MockChannel();
|
||||||
|
|
||||||
|
when(mockChannel.updateMessage(any)).thenAnswer((_) {
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final message = Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'image.jpg',
|
||||||
|
),
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'image.jpg',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: mockChannel,
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
message: message,
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.tap(find.text('Delete'));
|
||||||
|
verify(mockChannel.updateMessage(message.copyWith(
|
||||||
|
attachments: [
|
||||||
|
message.attachments[1],
|
||||||
|
],
|
||||||
|
))).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on delete in chat should remove the attachment if there is text',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final mockChannel = MockChannel();
|
||||||
|
|
||||||
|
when(mockChannel.updateMessage(any)).thenAnswer((_) {
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final message = Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'image.jpg',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: mockChannel,
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
message: message,
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.tap(find.text('Delete'));
|
||||||
|
verify(mockChannel.updateMessage(message.copyWith(
|
||||||
|
attachments: [],
|
||||||
|
))).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on delete in chat should remove the message if that\'s the only attachment and there is no text',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final mockChannel = MockChannel();
|
||||||
|
|
||||||
|
when(mockChannel.deleteMessage(any)).thenAnswer((_) {
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final message = Message(
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'image.jpg',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: mockChannel,
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
message: message,
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.tap(find.text('Delete'));
|
||||||
|
verify(mockChannel.deleteMessage(message)).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on save in chat should call image downloader',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final imageDownloader = MockAttachmentDownloader();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
home: Container(
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
imageDownloader: imageDownloader,
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'image.jpg',
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tap(find.text('Save Image'));
|
||||||
|
|
||||||
|
imageDownloader.progressCallback(0, 100);
|
||||||
|
await tester.pump();
|
||||||
|
expect(find.text('0%'), findsOneWidget);
|
||||||
|
|
||||||
|
imageDownloader.progressCallback(50, 100);
|
||||||
|
await tester.pump();
|
||||||
|
expect(find.text('50%'), findsOneWidget);
|
||||||
|
|
||||||
|
imageDownloader.progressCallback(100, 100);
|
||||||
|
imageDownloader.completer.complete('path');
|
||||||
|
await tester.pump();
|
||||||
|
expect(find.byKey(Key('completedIcon')), findsOneWidget);
|
||||||
|
await tester.pumpAndSettle(Duration(milliseconds: 500));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on save in chat should call file downloader',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final fileDownloader = MockAttachmentDownloader();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
home: Container(
|
||||||
|
child: AttachmentActionsModal(
|
||||||
|
fileDownloader: fileDownloader,
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
attachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'video',
|
||||||
|
title: 'video.mp4',
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
currentIndex: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tap(find.text('Save Video'));
|
||||||
|
|
||||||
|
fileDownloader.progressCallback(0, 100);
|
||||||
|
await tester.pump();
|
||||||
|
expect(find.text('0%'), findsOneWidget);
|
||||||
|
|
||||||
|
fileDownloader.progressCallback(50, 100);
|
||||||
|
await tester.pump();
|
||||||
|
expect(find.text('50%'), findsOneWidget);
|
||||||
|
|
||||||
|
fileDownloader.progressCallback(100, 100);
|
||||||
|
fileDownloader.completer.complete('path');
|
||||||
|
await tester.pump();
|
||||||
|
expect(find.byKey(Key('completedIcon')), findsOneWidget);
|
||||||
|
await tester.pumpAndSettle(Duration(milliseconds: 500));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show file details',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: StreamChatTheme(
|
||||||
|
data: streamTheme,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: FileAttachment(
|
||||||
|
size: Size(
|
||||||
|
300.0,
|
||||||
|
300.0,
|
||||||
|
),
|
||||||
|
message: Message(),
|
||||||
|
attachment: Attachment(
|
||||||
|
type: 'file',
|
||||||
|
title: 'example.pdf',
|
||||||
|
extraData: {
|
||||||
|
'mime_type': 'pdf',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.text('example.pdf'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/back_button.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'BackButton control test',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final theme = ThemeData();
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: const Material(child: Text('Home')),
|
||||||
|
routes: <String, WidgetBuilder>{
|
||||||
|
'/next': (BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
child: Center(
|
||||||
|
child: StreamChatTheme(
|
||||||
|
data: StreamChatThemeData.getDefaultTheme(theme),
|
||||||
|
child: StreamBackButton(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// ignore: unawaited_futures
|
||||||
|
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.byType(StreamBackButton));
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Home'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should not throw errors if cannot pop',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final theme = ThemeData();
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StreamChatTheme(
|
||||||
|
data: StreamChatThemeData.getDefaultTheme(theme),
|
||||||
|
child: StreamBackButton(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.byType(StreamBackButton));
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(StreamBackButton), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'BackButton onPressed overrides default pop behavior',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final theme = ThemeData();
|
||||||
|
var customCallbackWasCalled = false;
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: const Material(child: Text('Home')),
|
||||||
|
routes: <String, WidgetBuilder>{
|
||||||
|
'/next': (BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
child: Center(
|
||||||
|
child: StreamChatTheme(
|
||||||
|
data: StreamChatThemeData.getDefaultTheme(theme),
|
||||||
|
child: StreamBackButton(
|
||||||
|
onPressed: () => customCallbackWasCalled = true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// ignore: unawaited_futures
|
||||||
|
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Home'), findsNothing); // Start off on the second page.
|
||||||
|
expect(
|
||||||
|
customCallbackWasCalled,
|
||||||
|
false,
|
||||||
|
); // customCallbackWasCalled should still be false.
|
||||||
|
await tester.tap(find.byType(StreamBackButton));
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// We're still on the second page.
|
||||||
|
expect(find.text('Home'), findsNothing);
|
||||||
|
// But the custom callback is called.
|
||||||
|
expect(customCallbackWasCalled, true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show unread count',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamBackButton(
|
||||||
|
showUnreads: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.byType(UnreadIndicator), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,388 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/channel_info.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show basic channel information',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelHeader(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('test'), findsOneWidget);
|
||||||
|
expect(find.byType(ChannelImage), findsOneWidget);
|
||||||
|
expect(find.byType(StreamBackButton), findsOneWidget);
|
||||||
|
expect(find.byType(ChannelInfo), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show the InfoTile message if disconnected',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
when(client.wsConnectionStatusStream)
|
||||||
|
.thenAnswer((_) => Stream.value(ConnectionStatus.disconnected));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelHeader(
|
||||||
|
showConnectionStateTile: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.widget<InfoTile>(find.byType(InfoTile)).showMessage, true);
|
||||||
|
expect(tester.widget<InfoTile>(find.byType(InfoTile)).message,
|
||||||
|
'Disconnected');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show the InfoTile message if connecting',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
when(client.wsConnectionStatusStream)
|
||||||
|
.thenAnswer((_) => Stream.value(ConnectionStatus.connecting));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
showLoading: false,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelHeader(
|
||||||
|
showConnectionStateTile: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(tester.widget<InfoTile>(find.byType(InfoTile)).showMessage, true);
|
||||||
|
expect(tester.widget<InfoTile>(find.byType(InfoTile)).message,
|
||||||
|
'Reconnecting...');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should apply passed properties',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelHeader(
|
||||||
|
leading: Text('leading'),
|
||||||
|
subtitle: Text('subtitle'),
|
||||||
|
actions: [
|
||||||
|
Text('action'),
|
||||||
|
],
|
||||||
|
title: Text('title'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('test'), findsNothing);
|
||||||
|
expect(find.byType(StreamBackButton), findsNothing);
|
||||||
|
expect(find.byType(ChannelImage), findsNothing);
|
||||||
|
expect(find.byType(ChannelInfo), findsNothing);
|
||||||
|
expect(find.text('leading'), findsOneWidget);
|
||||||
|
expect(find.text('title'), findsOneWidget);
|
||||||
|
expect(find.text('subtitle'), findsOneWidget);
|
||||||
|
expect(find.text('action'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'showBackButton: false should hide the StreamBackButton and '
|
||||||
|
'showTypingIndicator: false should hide the typing indicator and '
|
||||||
|
'showConnectionStateTile: false should be passed to the infotile',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
when(client.wsConnectionStatusStream)
|
||||||
|
.thenAnswer((_) => Stream.value(ConnectionStatus.disconnected));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelHeader(
|
||||||
|
showTypingIndicator: false,
|
||||||
|
showBackButton: false,
|
||||||
|
showConnectionStateTile: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.byType(StreamBackButton), findsNothing);
|
||||||
|
expect(
|
||||||
|
tester
|
||||||
|
.widget<ChannelInfo>(find.byType(ChannelInfo))
|
||||||
|
.showTypingIndicator,
|
||||||
|
false);
|
||||||
|
expect(tester.widget<InfoTile>(find.byType(InfoTile)).showMessage, false);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'should apply passed callbacks',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
var backPressed = false;
|
||||||
|
var imageTapped = false;
|
||||||
|
var titleTapped = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelHeader(
|
||||||
|
onBackPressed: () => backPressed = true,
|
||||||
|
onImageTap: () => imageTapped = true,
|
||||||
|
onTitleTap: () => titleTapped = true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
await tester.tap(find.byType(StreamBackButton));
|
||||||
|
await tester.tap(find.byType(ChannelImage));
|
||||||
|
await tester.tap(find.byType(ChannelName));
|
||||||
|
|
||||||
|
expect(backPressed, true);
|
||||||
|
expect(imageTapped, true);
|
||||||
|
expect(titleTapped, true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/group_image.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show the image in channel.extraData',
|
||||||
|
(tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
'image': 'imagetest',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
'image': 'imagetest',
|
||||||
|
});
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelImage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
final image =
|
||||||
|
tester.widget<CachedNetworkImage>(find.byType(CachedNetworkImage));
|
||||||
|
expect(image.imageUrl, 'imagetest');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show the the other member image',
|
||||||
|
(tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
Member(
|
||||||
|
userId: 'user-id2',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id2',
|
||||||
|
extraData: {
|
||||||
|
'image': 'testimage',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id2',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id2',
|
||||||
|
extraData: {
|
||||||
|
'image': 'testimage',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
when(clientState.usersStream).thenAnswer((i) => Stream.value({
|
||||||
|
'user-id2': User(
|
||||||
|
id: 'user-id2',
|
||||||
|
extraData: {
|
||||||
|
'image': 'testimage',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelImage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
final image =
|
||||||
|
tester.widget<CachedNetworkImage>(find.byType(CachedNetworkImage));
|
||||||
|
expect(image.imageUrl, 'testimage');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should use a groupimage if more than 2 members',
|
||||||
|
(tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
extraData: {
|
||||||
|
'image': 'testimage1',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Member(
|
||||||
|
userId: 'user-id2',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id2',
|
||||||
|
extraData: {
|
||||||
|
'image': 'testimage2',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Member(
|
||||||
|
userId: 'user-id3',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id3',
|
||||||
|
extraData: {
|
||||||
|
'image': 'testimage3',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
extraData: {
|
||||||
|
'image': 'testimage1',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Member(
|
||||||
|
userId: 'user-id2',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id2',
|
||||||
|
extraData: {
|
||||||
|
'image': 'testimage2',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Member(
|
||||||
|
userId: 'user-id3',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id3',
|
||||||
|
extraData: {
|
||||||
|
'image': 'testimage3',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelImage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
final image = tester.widget<GroupImage>(find.byType(GroupImage));
|
||||||
|
expect(image.images, [
|
||||||
|
'testimage2',
|
||||||
|
'testimage3',
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'using select: true should show a selection border',
|
||||||
|
(tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
'image': 'imagetest',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
'image': 'imagetest',
|
||||||
|
});
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelImage(
|
||||||
|
selected: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.byKey(Key('selectedImage')), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'control test',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(client.wsConnectionStatusStream)
|
||||||
|
.thenAnswer((_) => Stream.value(ConnectionStatus.connected));
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelListHeader(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
final userAvatar = tester.widget<UserAvatar>(find.byType(UserAvatar));
|
||||||
|
expect(userAvatar.user, clientState.user);
|
||||||
|
expect(find.byType(StreamNeumorphicButton), findsOneWidget);
|
||||||
|
expect(find.text('Stream Chat'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show the InfoTile message if disconnected',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(client.wsConnectionStatusStream)
|
||||||
|
.thenAnswer((_) => Stream.value(ConnectionStatus.disconnected));
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelListHeader(
|
||||||
|
showConnectionStateTile: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Disconnected'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show the InfoTile message if connecting',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(client.wsConnectionStatusStream)
|
||||||
|
.thenAnswer((_) => Stream.value(ConnectionStatus.connecting));
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelListHeader(
|
||||||
|
showConnectionStateTile: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(find.text('Reconnecting...'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should apply passed properties',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(client.wsConnectionStatusStream)
|
||||||
|
.thenAnswer((_) => Stream.value(ConnectionStatus.connecting));
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelListHeader(
|
||||||
|
titleBuilder: (context, status, client) {
|
||||||
|
return Text('TITLE');
|
||||||
|
},
|
||||||
|
subtitle: Text('SUBTITLE'),
|
||||||
|
leading: Text('LEADING'),
|
||||||
|
actions: [
|
||||||
|
Text('ACTION'),
|
||||||
|
],
|
||||||
|
client: client,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(find.text('TITLE'), findsOneWidget);
|
||||||
|
expect(find.text('SUBTITLE'), findsOneWidget);
|
||||||
|
expect(find.text('LEADING'), findsOneWidget);
|
||||||
|
expect(find.text('ACTION'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should apply prenavigationcallback',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(client.wsConnectionStatusStream)
|
||||||
|
.thenAnswer((_) => Stream.value(ConnectionStatus.connecting));
|
||||||
|
|
||||||
|
var tapped = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelListHeader(
|
||||||
|
preNavigationCallback: () {
|
||||||
|
tapped = true;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
await tester.tap(find.byType(UserAvatar));
|
||||||
|
expect(tapped, true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should apply passed callbacks',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(client.wsConnectionStatusStream)
|
||||||
|
.thenAnswer((_) => Stream.value(ConnectionStatus.connecting));
|
||||||
|
|
||||||
|
var tapped = 0;
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelListHeader(
|
||||||
|
onUserAvatarTap: (u) {
|
||||||
|
tapped++;
|
||||||
|
},
|
||||||
|
onNewChatButtonTap: () {
|
||||||
|
tapped++;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
await tester.tap(find.byType(UserAvatar));
|
||||||
|
await tester.tap(find.byType(StreamNeumorphicButton));
|
||||||
|
expect(tapped, 2);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show channel name',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
when(channelState.messages).thenReturn([
|
||||||
|
Message(
|
||||||
|
text: 'hello',
|
||||||
|
user: User(id: 'other-user'),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
when(channelState.messagesStream).thenAnswer((i) => Stream.value([
|
||||||
|
Message(
|
||||||
|
text: 'hello',
|
||||||
|
user: User(id: 'other-user'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ChannelName(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('test'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ void main() {
|
|||||||
final channelState = MockChannelState();
|
final channelState = MockChannelState();
|
||||||
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(channel.cid).thenReturn('cid');
|
||||||
when(client.state).thenReturn(clientState);
|
when(client.state).thenReturn(clientState);
|
||||||
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
@@ -28,6 +29,9 @@ void main() {
|
|||||||
when(channel.extraData).thenReturn({
|
when(channel.extraData).thenReturn({
|
||||||
'name': 'test name',
|
'name': 'test name',
|
||||||
});
|
});
|
||||||
|
when(clientState.channels).thenReturn({
|
||||||
|
channel.cid: channel,
|
||||||
|
});
|
||||||
when(channelState.unreadCount).thenReturn(1);
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show basic channel information',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: DateDivider(
|
||||||
|
dateTime: DateTime.now(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('Today'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:golden_toolkit/golden_toolkit.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'control test',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: DeletedMessage(
|
||||||
|
messageTheme: MessageTheme(
|
||||||
|
createdAt: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
messageText: TextStyle(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('Message deleted'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testGoldens(
|
||||||
|
'control golden light',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
when(clientState.totalUnreadCount).thenReturn(10);
|
||||||
|
when(clientState.totalUnreadCountStream)
|
||||||
|
.thenAnswer((i) => Stream.value(10));
|
||||||
|
|
||||||
|
final materialTheme = ThemeData.light();
|
||||||
|
final theme = StreamChatThemeData.fromTheme(materialTheme);
|
||||||
|
await tester.pumpWidgetBuilder(
|
||||||
|
materialAppWrapper(
|
||||||
|
theme: materialTheme,
|
||||||
|
)(
|
||||||
|
StreamChat(
|
||||||
|
streamChatThemeData: theme,
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Center(
|
||||||
|
child: DeletedMessage(
|
||||||
|
messageTheme: theme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
surfaceSize: Size.square(200),
|
||||||
|
);
|
||||||
|
|
||||||
|
await screenMatchesGolden(tester, 'deleted_message_light');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testGoldens(
|
||||||
|
'control golden dark',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
when(clientState.totalUnreadCount).thenReturn(10);
|
||||||
|
when(clientState.totalUnreadCountStream)
|
||||||
|
.thenAnswer((i) => Stream.value(10));
|
||||||
|
|
||||||
|
final materialTheme = ThemeData.dark();
|
||||||
|
final theme = StreamChatThemeData.fromTheme(materialTheme);
|
||||||
|
await tester.pumpWidgetBuilder(
|
||||||
|
materialAppWrapper(
|
||||||
|
theme: materialTheme,
|
||||||
|
)(
|
||||||
|
StreamChat(
|
||||||
|
streamChatThemeData: theme,
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Center(
|
||||||
|
child: DeletedMessage(
|
||||||
|
messageTheme: theme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
surfaceSize: Size.square(200),
|
||||||
|
);
|
||||||
|
|
||||||
|
await screenMatchesGolden(tester, 'deleted_message_dark');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testGoldens(
|
||||||
|
'golden customization test',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
when(clientState.totalUnreadCount).thenReturn(10);
|
||||||
|
when(clientState.totalUnreadCountStream)
|
||||||
|
.thenAnswer((i) => Stream.value(10));
|
||||||
|
|
||||||
|
final materialTheme = ThemeData.light();
|
||||||
|
final theme = StreamChatThemeData.fromTheme(materialTheme);
|
||||||
|
await tester.pumpWidgetBuilder(
|
||||||
|
materialAppWrapper(
|
||||||
|
theme: materialTheme,
|
||||||
|
)(
|
||||||
|
StreamChat(
|
||||||
|
streamChatThemeData: theme,
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Center(
|
||||||
|
child: DeletedMessage(
|
||||||
|
messageTheme: theme.ownMessageTheme,
|
||||||
|
reverse: true,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
surfaceSize: Size.square(200),
|
||||||
|
);
|
||||||
|
|
||||||
|
await screenMatchesGolden(tester, 'deleted_message_custom');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:photo_view/photo_view.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show channel typing',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
when(channelState.messages).thenReturn([
|
||||||
|
Message(
|
||||||
|
text: 'hello',
|
||||||
|
user: User(id: 'other-user'),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
when(channelState.messagesStream).thenAnswer((i) => Stream.value([
|
||||||
|
Message(
|
||||||
|
text: 'hello',
|
||||||
|
user: User(id: 'other-user'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
|
||||||
|
when(channelState.typingEvents).thenAnswer((i) => [
|
||||||
|
User(id: 'other-user', extraData: {'name': 'demo'})
|
||||||
|
]);
|
||||||
|
when(channelState.typingEventsStream).thenAnswer((i) => Stream.value([
|
||||||
|
User(id: 'other-user', extraData: {'name': 'demo'}),
|
||||||
|
User(id: 'other-user', extraData: {'name': 'demo'}),
|
||||||
|
]));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: FullScreenMedia(
|
||||||
|
mediaAttachments: [
|
||||||
|
Attachment(
|
||||||
|
type: 'image',
|
||||||
|
title: 'demo image',
|
||||||
|
imageUrl: '',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
message: Message(
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
),
|
||||||
|
sentAt: DateTime.now(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.byType(PhotoView), findsOneWidget);
|
||||||
|
expect(find.byType(StreamSvgIcon), findsNWidgets(4));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 410 B |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,50 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show channel typing',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: WillPopScope(
|
||||||
|
onWillPop: () async => false,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ImageFooter(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.byType(StreamSvgIcon), findsNWidgets(2));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_portal/flutter_portal.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'control test',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: Portal(
|
||||||
|
child: Container(
|
||||||
|
child: InfoTile(
|
||||||
|
showMessage: true,
|
||||||
|
message: 'message',
|
||||||
|
child: Text('test'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('message'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should hide when passing showMessage: false',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: Scaffold(
|
||||||
|
body: Portal(
|
||||||
|
child: Container(
|
||||||
|
child: InfoTile(
|
||||||
|
showMessage: false,
|
||||||
|
message: 'message',
|
||||||
|
child: Text('test'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('message'), findsNothing);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -38,16 +38,17 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
await tester.pump();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
await tester.pump(Duration(milliseconds: 1000));
|
|
||||||
expect(find.byKey(Key('MessageWidget')), findsOneWidget);
|
expect(find.byKey(Key('MessageWidget')), findsOneWidget);
|
||||||
expect(find.text('Thread Reply'), findsOneWidget);
|
expect(find.text('Thread Reply'), findsOneWidget);
|
||||||
|
expect(find.text('Reply'), findsOneWidget);
|
||||||
expect(find.text('Edit Message'), findsOneWidget);
|
expect(find.text('Edit Message'), findsOneWidget);
|
||||||
expect(find.text('Delete Message'), findsOneWidget);
|
expect(find.text('Delete Message'), findsOneWidget);
|
||||||
expect(find.text('Copy Message'), findsOneWidget);
|
expect(find.text('Copy Message'), findsOneWidget);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'it should show some actions',
|
'it should show some actions',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
@@ -84,9 +85,8 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
await tester.pump();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
await tester.pump(Duration(milliseconds: 1000));
|
|
||||||
expect(find.byKey(Key('MessageWidget')), findsOneWidget);
|
expect(find.byKey(Key('MessageWidget')), findsOneWidget);
|
||||||
expect(find.text('Reply'), findsNothing);
|
expect(find.text('Reply'), findsNothing);
|
||||||
expect(find.text('Thread reply'), findsNothing);
|
expect(find.text('Thread reply'), findsNothing);
|
||||||
@@ -95,4 +95,697 @@ void main() {
|
|||||||
expect(find.text('Copy message'), findsNothing);
|
expect(find.text('Copy message'), findsNothing);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show custom actions',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
var tapped = false;
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
customActions: [
|
||||||
|
MessageAction(
|
||||||
|
leading: Icon(Icons.check),
|
||||||
|
title: Text('title'),
|
||||||
|
onTap: (m) {
|
||||||
|
tapped = true;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byIcon(Icons.check), findsOneWidget);
|
||||||
|
expect(find.text('title'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.text('title'));
|
||||||
|
|
||||||
|
expect(tapped, true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on reply should call the callback',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
var tapped = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
onReplyTap: (m) {
|
||||||
|
return tapped = true;
|
||||||
|
},
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Reply'));
|
||||||
|
|
||||||
|
expect(tapped, true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on thread reply should call the callback',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
var tapped = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
client: client,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
onThreadReplyTap: (m) {
|
||||||
|
return tapped = true;
|
||||||
|
},
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Thread Reply'));
|
||||||
|
|
||||||
|
expect(tapped, true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on edit should show the edit bottom sheet',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Edit Message'));
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(MessageInput), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on edit should show use the custom builder',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
editMessageInputBuilder: (context, m) {
|
||||||
|
return Text('test');
|
||||||
|
},
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Edit Message'));
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('test'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on copy should use the callback',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
var tapped = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
onCopyTap: (m) => tapped = true,
|
||||||
|
message: Message(
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Copy Message'));
|
||||||
|
|
||||||
|
expect(tapped, true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on resend should call send message',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
status: MessageSendingStatus.failed,
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Resend'));
|
||||||
|
|
||||||
|
verify(channel.sendMessage(any)).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on resend should call update message if editing the message',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
status: MessageSendingStatus.failed_update,
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Resend Edited Message'));
|
||||||
|
|
||||||
|
verify(channel.updateMessage(any)).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on flag message should show the dialog',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
id: 'testid',
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Flag Message'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Flag Message'), findsNWidgets(2));
|
||||||
|
|
||||||
|
await tester.tap(find.text('FLAG'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
verify(client.flagMessage('testid')).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'if flagging a message throws an error the error dialog should appear',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(client.flagMessage(any)).thenThrow(ApiError(
|
||||||
|
'{}',
|
||||||
|
500,
|
||||||
|
));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
id: 'testid',
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Flag Message'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Flag Message'), findsNWidgets(2));
|
||||||
|
|
||||||
|
await tester.tap(find.text('FLAG'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Something went wrong'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'if flagging an already flagged message no error should appear',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(client.flagMessage(any)).thenThrow(ApiError(
|
||||||
|
'{"code":4}',
|
||||||
|
400,
|
||||||
|
));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
id: 'testid',
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Flag Message'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Flag Message'), findsNWidgets(2));
|
||||||
|
|
||||||
|
await tester.tap(find.text('FLAG'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Message flagged'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on delete message should call client.delete',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
id: 'testid',
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Delete Message'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Delete message'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.text('DELETE'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
verify(channel.deleteMessage(any)).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'tapping on delete message should call client.delete',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(channel.deleteMessage(any)).thenThrow(ApiError(
|
||||||
|
'{}',
|
||||||
|
500,
|
||||||
|
));
|
||||||
|
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
builder: (context, child) {
|
||||||
|
return StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Container(
|
||||||
|
child: MessageActionsModal(
|
||||||
|
message: Message(
|
||||||
|
id: 'testid',
|
||||||
|
text: 'test',
|
||||||
|
user: User(
|
||||||
|
id: 'user-id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('Delete Message'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Delete message'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.text('DELETE'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('Something went wrong'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'checks message input features',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
when(channelState.messages).thenReturn([
|
||||||
|
Message(
|
||||||
|
text: 'hello',
|
||||||
|
user: User(id: 'other-user'),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
when(channelState.messagesStream).thenAnswer((i) => Stream.value([
|
||||||
|
Message(
|
||||||
|
text: 'hello',
|
||||||
|
user: User(id: 'other-user'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
|
||||||
|
when(channelState.typingEvents).thenAnswer((i) => [
|
||||||
|
User(id: 'other-user', extraData: {'name': 'demo'})
|
||||||
|
]);
|
||||||
|
when(channelState.typingEventsStream).thenAnswer((i) => Stream.value([
|
||||||
|
User(id: 'other-user', extraData: {'name': 'demo'}),
|
||||||
|
User(id: 'other-user', extraData: {'name': 'demo'}),
|
||||||
|
]));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: MessageInput(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.byType(TextField), findsOneWidget);
|
||||||
|
expect(find.byType(StreamSvgIcon), findsNWidgets(8));
|
||||||
|
expect(find.byKey(Key('messageInputText')), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:mockito/mockito.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/message_reactions_modal.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
import 'mocks.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets(
|
|
||||||
'it should show one thumbs from the picker',
|
|
||||||
(WidgetTester tester) async {
|
|
||||||
final client = MockClient();
|
|
||||||
final clientState = MockClientState();
|
|
||||||
final themeData = ThemeData();
|
|
||||||
|
|
||||||
when(client.state).thenReturn(clientState);
|
|
||||||
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
|
||||||
|
|
||||||
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
MaterialApp(
|
|
||||||
theme: themeData,
|
|
||||||
home: StreamChat(
|
|
||||||
client: client,
|
|
||||||
streamChatThemeData: streamTheme,
|
|
||||||
child: MessageReactionsModal(
|
|
||||||
message: Message(
|
|
||||||
id: 'test',
|
|
||||||
text: 'test message',
|
|
||||||
user: User(
|
|
||||||
id: 'test-user',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
messageTheme: streamTheme.ownMessageTheme,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.pump(Duration(milliseconds: 1000));
|
|
||||||
|
|
||||||
expect(find.byKey(Key('MessageWidget')), findsOneWidget);
|
|
||||||
expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')),
|
|
||||||
findsOneWidget);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
testWidgets(
|
|
||||||
'it should show two reactions',
|
|
||||||
(WidgetTester tester) async {
|
|
||||||
final client = MockClient();
|
|
||||||
final clientState = MockClientState();
|
|
||||||
|
|
||||||
when(client.state).thenReturn(clientState);
|
|
||||||
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
|
||||||
|
|
||||||
final themeData = ThemeData();
|
|
||||||
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
|
||||||
final testUserId = 'test user';
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
MaterialApp(
|
|
||||||
theme: themeData,
|
|
||||||
home: StreamChat(
|
|
||||||
streamChatThemeData: streamTheme,
|
|
||||||
client: client,
|
|
||||||
child: MessageReactionsModal(
|
|
||||||
message: Message(
|
|
||||||
text: 'test message',
|
|
||||||
user: User(
|
|
||||||
id: 'test-user',
|
|
||||||
),
|
|
||||||
latestReactions: [
|
|
||||||
Reaction(
|
|
||||||
type: 'like',
|
|
||||||
user: User(id: testUserId),
|
|
||||||
),
|
|
||||||
Reaction(
|
|
||||||
type: 'love',
|
|
||||||
user: User(id: testUserId),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
messageTheme: streamTheme.ownMessageTheme,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
await tester.pump(Duration(milliseconds: 1000));
|
|
||||||
expect(find.byKey(Key('MessageWidget')), findsOneWidget);
|
|
||||||
expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')),
|
|
||||||
findsNWidgets(2));
|
|
||||||
expect(find.byKey(Key('StreamSvgIcon-Icon_love_reaction.svg')),
|
|
||||||
findsNWidgets(2));
|
|
||||||
expect(find.text(testUserId.split(' ')[0]), findsNWidgets(2));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/message_reactions_modal.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'control test',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final themeData = ThemeData();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
final message = Message(
|
||||||
|
id: 'test',
|
||||||
|
text: 'test message',
|
||||||
|
user: User(
|
||||||
|
id: 'test-user',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: MessageReactionsModal(
|
||||||
|
message: message,
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pump(Duration(milliseconds: 1000));
|
||||||
|
|
||||||
|
expect(find.byType(MessageWidget), findsOneWidget);
|
||||||
|
final messageWidget =
|
||||||
|
tester.widget<MessageWidget>(find.byType(MessageWidget));
|
||||||
|
expect(messageWidget.message, message);
|
||||||
|
expect(messageWidget.messageTheme, streamTheme.ownMessageTheme);
|
||||||
|
expect(messageWidget.attachmentBorderRadiusGeometry, null);
|
||||||
|
expect(messageWidget.showUserAvatar, DisplayWidget.show);
|
||||||
|
expect(messageWidget.reverse, false);
|
||||||
|
expect(messageWidget.attachmentShape, null);
|
||||||
|
expect(messageWidget.shape, null);
|
||||||
|
expect(messageWidget.onUserAvatarTap, null);
|
||||||
|
expect(messageWidget.showReactions, false);
|
||||||
|
expect(messageWidget.showUsername, false);
|
||||||
|
expect(messageWidget.showThreadReplyIndicator, false);
|
||||||
|
expect(messageWidget.showTimestamp, false);
|
||||||
|
expect(messageWidget.translateUserAvatar, false);
|
||||||
|
expect(messageWidget.showSendingIndicator, false);
|
||||||
|
|
||||||
|
expect(find.byType(ReactionBubble), findsNothing);
|
||||||
|
|
||||||
|
//only one avatar (the message one)
|
||||||
|
expect(find.byType(UserAvatar), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should apply passed parameters',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final themeData = ThemeData();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
final message = Message(
|
||||||
|
id: 'test',
|
||||||
|
text: 'test message',
|
||||||
|
user: User(
|
||||||
|
id: 'test-user',
|
||||||
|
),
|
||||||
|
latestReactions: [
|
||||||
|
Reaction(
|
||||||
|
messageId: 'test',
|
||||||
|
user: User(id: 'testid'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
final onUserAvatarTap = (u) => print('ok');
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: themeData,
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: streamTheme,
|
||||||
|
child: MessageReactionsModal(
|
||||||
|
message: message,
|
||||||
|
messageTheme: streamTheme.ownMessageTheme,
|
||||||
|
showUserAvatar: DisplayWidget.gone,
|
||||||
|
reverse: true,
|
||||||
|
attachmentBorderRadiusGeometry: BorderRadius.circular(1),
|
||||||
|
attachmentShape: RoundedRectangleBorder(),
|
||||||
|
showReactions: false,
|
||||||
|
messageShape: RoundedRectangleBorder(),
|
||||||
|
onUserAvatarTap: onUserAvatarTap,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pump(Duration(milliseconds: 1000));
|
||||||
|
|
||||||
|
expect(find.byType(MessageWidget), findsOneWidget);
|
||||||
|
final messageWidget =
|
||||||
|
tester.widget<MessageWidget>(find.byType(MessageWidget));
|
||||||
|
expect(messageWidget.message, message);
|
||||||
|
expect(messageWidget.messageTheme, streamTheme.ownMessageTheme);
|
||||||
|
expect(messageWidget.attachmentBorderRadiusGeometry,
|
||||||
|
BorderRadius.circular(1));
|
||||||
|
expect(messageWidget.showUserAvatar, DisplayWidget.gone);
|
||||||
|
expect(messageWidget.reverse, true);
|
||||||
|
expect(messageWidget.showReactions, false);
|
||||||
|
expect(messageWidget.attachmentShape, RoundedRectangleBorder());
|
||||||
|
expect(messageWidget.shape, RoundedRectangleBorder());
|
||||||
|
expect(messageWidget.showReactions, false);
|
||||||
|
expect(messageWidget.showUsername, false);
|
||||||
|
expect(messageWidget.showThreadReplyIndicator, false);
|
||||||
|
expect(messageWidget.showTimestamp, false);
|
||||||
|
expect(messageWidget.translateUserAvatar, false);
|
||||||
|
expect(messageWidget.showSendingIndicator, false);
|
||||||
|
|
||||||
|
final userAvatar = tester.widget<UserAvatar>(find.byType(UserAvatar));
|
||||||
|
expect(userAvatar.onTap, onUserAvatarTap);
|
||||||
|
|
||||||
|
expect(find.byType(ReactionBubble), findsOneWidget);
|
||||||
|
expect(find.byType(UserAvatar), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show correct message text',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
final themeData = ThemeData();
|
||||||
|
final streamTheme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: MessageText(
|
||||||
|
message: Message(
|
||||||
|
text: 'demo',
|
||||||
|
),
|
||||||
|
messageTheme: streamTheme.otherMessageTheme),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.byType(MarkdownBody), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
@@ -8,3 +9,9 @@ class MockClientState extends Mock implements ClientState {}
|
|||||||
class MockChannel extends Mock implements Channel {}
|
class MockChannel extends Mock implements Channel {}
|
||||||
|
|
||||||
class MockChannelState extends Mock implements ChannelClientState {}
|
class MockChannelState extends Mock implements ChannelClientState {}
|
||||||
|
|
||||||
|
class MockNavigatorObserver extends Mock implements NavigatorObserver {}
|
||||||
|
|
||||||
|
class MockVoidCallback extends Mock {
|
||||||
|
void call();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:golden_toolkit/golden_toolkit.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
|
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import 'mocks.dart';
|
import 'mocks.dart';
|
||||||
|
import 'simple_frame.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets(
|
testGoldens(
|
||||||
'it should show no reactions',
|
'it should show no reactions',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidgetBuilder(
|
||||||
MaterialApp(
|
SimpleFrame(
|
||||||
home: StreamChatTheme(
|
child: StreamChatTheme(
|
||||||
data: StreamChatThemeData(),
|
data: StreamChatThemeData(),
|
||||||
child: Container(
|
child: Container(
|
||||||
child: ReactionBubble(
|
child: ReactionBubble(
|
||||||
@@ -24,15 +26,173 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
surfaceSize: Size(100, 100),
|
||||||
);
|
);
|
||||||
|
await screenMatchesGolden(tester, 'reaction_bubble_0');
|
||||||
expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')),
|
|
||||||
findsNothing);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
testWidgets(
|
testGoldens(
|
||||||
'it should show a like',
|
'it should show a like - light theme',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final themeData = ThemeData.light();
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
final theme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
await tester.pumpWidgetBuilder(
|
||||||
|
StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: theme,
|
||||||
|
child: Container(
|
||||||
|
child: ReactionBubble(
|
||||||
|
reactions: [
|
||||||
|
Reaction(
|
||||||
|
type: 'like',
|
||||||
|
user: User(id: 'test'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
borderColor: theme.ownMessageTheme.reactionsBorderColor,
|
||||||
|
backgroundColor: theme.ownMessageTheme.reactionsBackgroundColor,
|
||||||
|
maskColor: theme.ownMessageTheme.reactionsMaskColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
surfaceSize: Size(100, 100),
|
||||||
|
);
|
||||||
|
await screenMatchesGolden(tester, 'reaction_bubble_like_light');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testGoldens(
|
||||||
|
'it should show a like - dark theme',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final themeData = ThemeData.dark();
|
||||||
|
final theme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
await tester.pumpWidgetBuilder(
|
||||||
|
StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black,
|
||||||
|
child: ReactionBubble(
|
||||||
|
reactions: [
|
||||||
|
Reaction(
|
||||||
|
type: 'like',
|
||||||
|
user: User(id: 'test'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
borderColor: theme.ownMessageTheme.reactionsBorderColor,
|
||||||
|
backgroundColor: theme.ownMessageTheme.reactionsBackgroundColor,
|
||||||
|
maskColor: theme.ownMessageTheme.reactionsMaskColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
surfaceSize: Size(100, 100),
|
||||||
|
);
|
||||||
|
await screenMatchesGolden(tester, 'reaction_bubble_like_dark');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testGoldens(
|
||||||
|
'it should show three reactions - light theme',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final themeData = ThemeData.light();
|
||||||
|
final theme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
await tester.pumpWidgetBuilder(
|
||||||
|
StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black,
|
||||||
|
child: ReactionBubble(
|
||||||
|
reactions: [
|
||||||
|
Reaction(
|
||||||
|
type: 'like',
|
||||||
|
user: User(id: 'test'),
|
||||||
|
),
|
||||||
|
Reaction(
|
||||||
|
type: 'like',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
Reaction(
|
||||||
|
type: 'like',
|
||||||
|
user: User(id: 'test'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
borderColor: theme.ownMessageTheme.reactionsBorderColor,
|
||||||
|
backgroundColor: theme.ownMessageTheme.reactionsBackgroundColor,
|
||||||
|
maskColor: theme.ownMessageTheme.reactionsMaskColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
surfaceSize: Size(140, 140),
|
||||||
|
);
|
||||||
|
await screenMatchesGolden(tester, 'reaction_bubble_3_light');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testGoldens(
|
||||||
|
'it should show three reactions - dark theme',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final themeData = ThemeData.dark();
|
||||||
|
final theme = StreamChatThemeData.getDefaultTheme(themeData);
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
|
await tester.pumpWidgetBuilder(
|
||||||
|
StreamChat(
|
||||||
|
client: client,
|
||||||
|
streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black,
|
||||||
|
child: ReactionBubble(
|
||||||
|
reactions: [
|
||||||
|
Reaction(
|
||||||
|
type: 'like',
|
||||||
|
user: User(id: 'test'),
|
||||||
|
),
|
||||||
|
Reaction(
|
||||||
|
type: 'like',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
Reaction(
|
||||||
|
type: 'like',
|
||||||
|
user: User(id: 'test'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
borderColor: theme.ownMessageTheme.reactionsBorderColor,
|
||||||
|
backgroundColor: theme.ownMessageTheme.reactionsBackgroundColor,
|
||||||
|
maskColor: theme.ownMessageTheme.reactionsMaskColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
surfaceSize: Size(140, 140),
|
||||||
|
);
|
||||||
|
await screenMatchesGolden(tester, 'reaction_bubble_3_dark');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testGoldens(
|
||||||
|
'it should show two reactions with customized ui',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
final clientState = MockClientState();
|
final clientState = MockClientState();
|
||||||
@@ -41,74 +201,40 @@ void main() {
|
|||||||
when(client.state).thenReturn(clientState);
|
when(client.state).thenReturn(clientState);
|
||||||
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidgetBuilder(
|
||||||
MaterialApp(
|
StreamChat(
|
||||||
theme: themeData,
|
client: client,
|
||||||
home: StreamChat(
|
streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData),
|
||||||
client: client,
|
child: Container(
|
||||||
streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData),
|
child: ReactionBubble(
|
||||||
child: Container(
|
reactions: [
|
||||||
child: ReactionBubble(
|
Reaction(
|
||||||
reactions: [
|
type: 'like',
|
||||||
Reaction(
|
user: User(id: 'test'),
|
||||||
type: 'like',
|
),
|
||||||
user: User(id: 'test'),
|
Reaction(
|
||||||
),
|
type: 'love',
|
||||||
],
|
user: User(id: 'user-id'),
|
||||||
borderColor: Colors.black,
|
),
|
||||||
backgroundColor: Colors.white,
|
Reaction(
|
||||||
maskColor: Colors.white,
|
type: 'unknown',
|
||||||
),
|
user: User(id: 'test'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
borderColor: Colors.red,
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
maskColor: Colors.green,
|
||||||
|
highlightOwnReactions: true,
|
||||||
|
reverse: true,
|
||||||
|
flipTail: true,
|
||||||
|
tailCirclesSpacing: 4,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
surfaceSize: Size(200, 200),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')),
|
await screenMatchesGolden(tester, 'reaction_bubble_2');
|
||||||
findsOneWidget);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
testWidgets(
|
|
||||||
'it should show two reactions',
|
|
||||||
(WidgetTester tester) async {
|
|
||||||
final client = MockClient();
|
|
||||||
final clientState = MockClientState();
|
|
||||||
final themeData = ThemeData();
|
|
||||||
|
|
||||||
when(client.state).thenReturn(clientState);
|
|
||||||
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
MaterialApp(
|
|
||||||
theme: themeData,
|
|
||||||
home: StreamChat(
|
|
||||||
client: client,
|
|
||||||
streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData),
|
|
||||||
child: Container(
|
|
||||||
child: ReactionBubble(
|
|
||||||
reactions: [
|
|
||||||
Reaction(
|
|
||||||
type: 'like',
|
|
||||||
user: User(id: 'test'),
|
|
||||||
),
|
|
||||||
Reaction(
|
|
||||||
type: 'love',
|
|
||||||
user: User(id: 'test'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
borderColor: Colors.black,
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
maskColor: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')),
|
|
||||||
findsOneWidget);
|
|
||||||
expect(find.byKey(Key('StreamSvgIcon-Icon_love_reaction.svg')),
|
|
||||||
findsOneWidget);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SimpleFrame extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
const SimpleFrame({Key key, @required this.child}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFFFFFFF),
|
||||||
|
border: Border.all(color: const Color(0xFF9E9E9E)),
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:golden_toolkit/golden_toolkit.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show total unread count',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
when(clientState.totalUnreadCount).thenReturn(10);
|
||||||
|
when(clientState.totalUnreadCountStream)
|
||||||
|
.thenAnswer((i) => Stream.value(10));
|
||||||
|
|
||||||
|
var tapped = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: SystemMessage(
|
||||||
|
onMessageTap: (m) => tapped = true,
|
||||||
|
message: Message(
|
||||||
|
text: 'demo message',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
await tester.tap(find.byType(SystemMessage));
|
||||||
|
|
||||||
|
expect(find.text('demo message'), findsOneWidget);
|
||||||
|
expect(tapped, true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testGoldens(
|
||||||
|
'control golden light',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
when(clientState.totalUnreadCount).thenReturn(10);
|
||||||
|
when(clientState.totalUnreadCountStream)
|
||||||
|
.thenAnswer((i) => Stream.value(10));
|
||||||
|
|
||||||
|
await tester.pumpWidgetBuilder(
|
||||||
|
materialAppWrapper(
|
||||||
|
theme: ThemeData.light(),
|
||||||
|
)(
|
||||||
|
StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Center(
|
||||||
|
child: SystemMessage(
|
||||||
|
message: Message(
|
||||||
|
text: 'demo message',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
surfaceSize: Size.square(200),
|
||||||
|
);
|
||||||
|
|
||||||
|
await screenMatchesGolden(tester, 'system_message_light');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testGoldens(
|
||||||
|
'control golden dark',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
when(clientState.totalUnreadCount).thenReturn(10);
|
||||||
|
when(clientState.totalUnreadCountStream)
|
||||||
|
.thenAnswer((i) => Stream.value(10));
|
||||||
|
|
||||||
|
await tester.pumpWidgetBuilder(
|
||||||
|
materialAppWrapper(
|
||||||
|
theme: ThemeData.dark(),
|
||||||
|
)(
|
||||||
|
StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
showLoading: false,
|
||||||
|
channel: channel,
|
||||||
|
child: Center(
|
||||||
|
child: SystemMessage(
|
||||||
|
message: Message(
|
||||||
|
text: 'demo message',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
surfaceSize: Size.square(200),
|
||||||
|
);
|
||||||
|
|
||||||
|
await screenMatchesGolden(tester, 'system_message_dark');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'control test',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ThreadHeader(
|
||||||
|
parent: Message(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('with '), findsOneWidget);
|
||||||
|
expect(find.byType(ChannelName), findsOneWidget);
|
||||||
|
expect(find.byType(StreamBackButton), findsOneWidget);
|
||||||
|
expect(find.text('Thread Reply'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should apply passed props',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.initialized).thenAnswer((_) => Future.value(true));
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.unreadCount).thenReturn(1);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1));
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
var tapped = false;
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: ThreadHeader(
|
||||||
|
parent: Message(),
|
||||||
|
subtitle: Text('subtitle'),
|
||||||
|
leading: Text('leading'),
|
||||||
|
title: Text('title'),
|
||||||
|
onTitleTap: () {
|
||||||
|
tapped = true;
|
||||||
|
},
|
||||||
|
actions: [
|
||||||
|
Text('action'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('title'), findsOneWidget);
|
||||||
|
await tester.tap(find.text('title'));
|
||||||
|
expect(tapped, true);
|
||||||
|
expect(find.text('subtitle'), findsOneWidget);
|
||||||
|
expect(find.text('action'), findsOneWidget);
|
||||||
|
expect(find.text('leading'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show channel typing',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.isMuted).thenReturn(false);
|
||||||
|
when(channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
when(channelState.membersStream).thenAnswer((i) => Stream.value([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
when(channelState.members).thenReturn([
|
||||||
|
Member(
|
||||||
|
userId: 'user-id',
|
||||||
|
user: User(id: 'user-id'),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
when(channelState.messages).thenReturn([
|
||||||
|
Message(
|
||||||
|
text: 'hello',
|
||||||
|
user: User(id: 'other-user'),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
when(channelState.messagesStream).thenAnswer((i) => Stream.value([
|
||||||
|
Message(
|
||||||
|
text: 'hello',
|
||||||
|
user: User(id: 'other-user'),
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
|
||||||
|
when(channelState.typingEvents).thenAnswer((i) => [
|
||||||
|
User(id: 'other-user', extraData: {'name': 'demo'})
|
||||||
|
]);
|
||||||
|
when(channelState.typingEventsStream).thenAnswer((i) => Stream.value([
|
||||||
|
User(id: 'other-user', extraData: {'name': 'demo'}),
|
||||||
|
User(id: 'other-user', extraData: {'name': 'demo'}),
|
||||||
|
]));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: TypingIndicator(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.byKey(Key('typings')), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'mocks.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets(
|
||||||
|
'it should show total unread count',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channel.extraDataStream).thenAnswer((i) => Stream.value({
|
||||||
|
'name': 'test',
|
||||||
|
}));
|
||||||
|
when(channel.extraData).thenReturn({
|
||||||
|
'name': 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
when(clientState.totalUnreadCount).thenReturn(10);
|
||||||
|
when(clientState.totalUnreadCountStream)
|
||||||
|
.thenAnswer((i) => Stream.value(10));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: UnreadIndicator(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('10'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show nothing if no unread messages',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
when(channel.cid).thenReturn('cid');
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(clientState.channels).thenReturn({
|
||||||
|
channel.cid: channel,
|
||||||
|
});
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channelState.unreadCount).thenReturn(0);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(0));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: UnreadIndicator(
|
||||||
|
cid: channel.cid,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.byType(SizedBox), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'it should show 99+ if more than 99 unreads',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final client = MockClient();
|
||||||
|
final clientState = MockClientState();
|
||||||
|
final channel = MockChannel();
|
||||||
|
when(channel.cid).thenReturn('cid');
|
||||||
|
final channelState = MockChannelState();
|
||||||
|
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
||||||
|
|
||||||
|
when(client.state).thenReturn(clientState);
|
||||||
|
when(clientState.user).thenReturn(OwnUser(id: 'user-id'));
|
||||||
|
when(clientState.channels).thenReturn({
|
||||||
|
channel.cid: channel,
|
||||||
|
});
|
||||||
|
when(channel.lastMessageAt).thenReturn(lastMessageAt);
|
||||||
|
when(channel.state).thenReturn(channelState);
|
||||||
|
when(channel.client).thenReturn(client);
|
||||||
|
when(channelState.unreadCount).thenReturn(100);
|
||||||
|
when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(100));
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: StreamChannel(
|
||||||
|
channel: channel,
|
||||||
|
child: Scaffold(
|
||||||
|
body: UnreadIndicator(
|
||||||
|
cid: channel.cid,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(find.text('99+'), findsOneWidget);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||