Implemented StreamAttachmentPackage and fixed operations in widgets linked to full screen implementation, also fixed tests

This commit is contained in:
Ayush Shekhar
2022-04-13 18:02:49 +05:30
parent 65a5af7b6c
commit 180c24ae72
18 changed files with 373 additions and 253 deletions
-1
View File
@@ -91,7 +91,6 @@ linter:
- prefer_constructors_over_static_methods
- prefer_contains
- prefer_equal_for_default_values
- prefer_expression_function_bodies
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
@@ -250,10 +250,9 @@ class StreamGiphyAttachment extends StreamAttachmentWidget {
return StreamChannel(
channel: channel,
child: StreamFullScreenMedia(
mediaAttachments: message.attachments,
mediaAttachmentPackages: message.getAttachmentPackageList(),
startIndex: message.attachments.indexOf(attachment),
userName: message.user?.name,
message: message,
onShowMessage: onShowMessage,
),
);
@@ -144,11 +144,11 @@ class StreamImageAttachment extends StreamAttachmentWidget {
return StreamChannel(
channel: channel,
child: StreamFullScreenMedia(
mediaAttachments: message.attachments,
mediaAttachmentPackages:
message.getAttachmentPackageList(),
startIndex:
message.attachments.indexOf(attachment),
userName: message.user?.name,
message: message,
onShowMessage: onShowMessage,
),
);
@@ -91,11 +91,11 @@ class StreamVideoAttachment extends StreamAttachmentWidget {
builder: (_) => StreamChannel(
channel: channel,
child: StreamFullScreenMedia(
mediaAttachments: message.attachments,
mediaAttachmentPackages:
message.getAttachmentPackageList(),
startIndex:
message.attachments.indexOf(attachment),
userName: message.user?.name,
message: message,
onShowMessage: onShowMessage,
),
),
@@ -9,14 +9,18 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
typedef AttachmentDownloader = Future<String> Function(
Attachment attachment, {
ProgressCallback? progressCallback,
DownloadedPathCallback? downloadedPathCallback,
});
/// Callback to receive the path once the attachment asset is downloaded
typedef DownloadedPathCallback = void Function(String? path);
/// Widget that shows the options in the gallery view
class AttachmentActionsModal extends StatelessWidget {
/// Returns a new [AttachmentActionsModal]
const AttachmentActionsModal({
Key? key,
required this.currentIndex,
required this.attachment,
required this.message,
this.onShowMessage,
this.imageDownloader,
@@ -28,12 +32,12 @@ class AttachmentActionsModal extends StatelessWidget {
this.customActions = const [],
}) : super(key: key);
/// The attachment object for which the actions are to be performed
final Attachment attachment;
/// The message containing the attachments
final Message message;
/// Current page index
final int currentIndex;
/// Callback to show the message
final VoidCallback? onShowMessage;
@@ -62,7 +66,7 @@ class AttachmentActionsModal extends StatelessWidget {
/// specified attributes overridden.
AttachmentActionsModal copyWith({
Key? key,
int? currentIndex,
Attachment? attachment,
Message? message,
VoidCallback? onShowMessage,
AttachmentDownloader? imageDownloader,
@@ -75,7 +79,7 @@ class AttachmentActionsModal extends StatelessWidget {
}) =>
AttachmentActionsModal(
key: key ?? this.key,
currentIndex: currentIndex ?? this.currentIndex,
attachment: attachment ?? this.attachment,
message: message ?? this.message,
onShowMessage: onShowMessage ?? this.onShowMessage,
imageDownloader: imageDownloader ?? this.imageDownloader,
@@ -138,7 +142,7 @@ class AttachmentActionsModal extends StatelessWidget {
if (showSave)
_buildButton(
context,
message.attachments[currentIndex].type == 'video'
attachment.type == 'video'
? context.translations.saveVideoLabel
: context.translations.saveImageLabel,
StreamSvgIcon.iconSave(
@@ -146,15 +150,16 @@ class AttachmentActionsModal extends StatelessWidget {
color: theme.colorTheme.textLowEmphasis,
),
() {
final attachment = message.attachments[currentIndex];
final isImage = attachment.type == 'image';
final Future<String?> Function(
Attachment, {
void Function(int, int) progressCallback,
DownloadedPathCallback downloadedPathCallback,
}) saveFile = fileDownloader ?? _downloadAttachment;
final Future<String?> Function(
Attachment, {
void Function(int, int) progressCallback,
DownloadedPathCallback downloadedPathCallback,
}) saveImage = imageDownloader ?? _downloadAttachment;
final downloader = isImage ? saveImage : saveFile;
@@ -162,15 +167,25 @@ class AttachmentActionsModal extends StatelessWidget {
ValueNotifier<_DownloadProgress?>(
_DownloadProgress.initial(),
);
final downloadedPathNotifier = ValueNotifier<String?>(
null,
);
downloader(
attachment,
progressCallback: (received, total) {
print('>>>>>>>>>>>>>>>');
print('>>r : $received');
print('>>t : $total');
print('>>>>>>>>>>>>>>>');
progressNotifier.value = _DownloadProgress(
total,
received,
);
},
downloadedPathCallback: (String? path) {
downloadedPathNotifier.value = path;
},
).catchError((e, stk) {
progressNotifier.value = null;
});
@@ -186,6 +201,7 @@ class AttachmentActionsModal extends StatelessWidget {
builder: (context) => _buildDownloadProgressDialog(
context,
progressNotifier,
downloadedPathNotifier,
),
);
},
@@ -204,8 +220,12 @@ class AttachmentActionsModal extends StatelessWidget {
final channel = StreamChannel.of(context).channel;
if (message.attachments.length > 1 ||
message.text?.isNotEmpty == true) {
final currentAttachmentIndex =
message.attachments.indexWhere(
(element) => element.id == attachment.id,
);
final remainingAttachments = [...message.attachments]
..removeAt(currentIndex);
..removeAt(currentAttachmentIndex);
channel.updateMessage(message.copyWith(
attachments: remainingAttachments,
));
@@ -285,73 +305,86 @@ class AttachmentActionsModal extends StatelessWidget {
Widget _buildDownloadProgressDialog(
BuildContext context,
ValueNotifier<_DownloadProgress?> progressNotifier,
ValueNotifier<String?> downloadedFilePathNotifier,
) {
final theme = StreamChatTheme.of(context);
return ValueListenableBuilder(
valueListenable: progressNotifier,
builder: (_, _DownloadProgress? progress, __) {
// Pop the dialog in case the progress is null or it's completed.
if (progress == null || progress.toProgressIndicatorValue == 1.0) {
valueListenable: downloadedFilePathNotifier,
builder: (_, String? path, __) {
final _downloadComplete = path != null && path.isNotEmpty;
// Pop the dialog in case the download has completed
if (_downloadComplete) {
Future.delayed(
const Duration(milliseconds: 500),
() => Navigator.of(context).maybePop(),
);
}
return Material(
type: MaterialType.transparency,
child: Center(
child: Container(
height: 182,
width: 182,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: theme.colorTheme.barsBg,
),
return ValueListenableBuilder(
valueListenable: progressNotifier,
builder: (_, _DownloadProgress? progress, __) {
// Pop the dialog in case the progress is null.
if (progress == null) {
Future.delayed(
const Duration(milliseconds: 500),
() => Navigator.of(context).maybePop(),
);
}
return Material(
type: MaterialType.transparency,
child: Center(
child: progress == null
? SizedBox(
height: 100,
width: 100,
child: StreamSvgIcon.error(
color: theme.colorTheme.disabled,
),
)
: progress.toProgressIndicatorValue == 1.0
child: Container(
height: 182,
width: 182,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: theme.colorTheme.barsBg,
),
child: Center(
child: progress == null
? SizedBox(
key: const Key('completedIcon'),
height: 160,
width: 160,
child: StreamSvgIcon.check(
height: 100,
width: 100,
child: StreamSvgIcon.error(
color: theme.colorTheme.disabled,
),
)
: SizedBox(
height: 100,
width: 100,
child: Stack(
fit: StackFit.expand,
children: [
CircularProgressIndicator(
value: progress.toProgressIndicatorValue,
strokeWidth: 8,
valueColor: AlwaysStoppedAnimation(
theme.colorTheme.accentPrimary,
),
: _downloadComplete
? SizedBox(
key: const Key('completedIcon'),
height: 160,
width: 160,
child: StreamSvgIcon.check(
color: theme.colorTheme.disabled,
),
Center(
child: Text(
'${progress.toPercentage}%',
style: theme.textTheme.headline.copyWith(
color: theme.colorTheme.textLowEmphasis,
)
: SizedBox(
height: 100,
width: 100,
child: Stack(
fit: StackFit.expand,
children: [
CircularProgressIndicator(
strokeWidth: 8,
color: theme.colorTheme.accentPrimary,
),
),
Center(
child: Text(
'${progress.receivedValueInMB} MB',
style:
theme.textTheme.headline.copyWith(
color:
theme.colorTheme.textLowEmphasis,
),
),
),
],
),
],
),
),
),
),
),
),
),
),
);
},
);
},
);
@@ -360,6 +393,7 @@ class AttachmentActionsModal extends StatelessWidget {
Future<String?> _downloadAttachment(
Attachment attachment, {
ProgressCallback? progressCallback,
DownloadedPathCallback? downloadedPathCallback,
}) async {
String? filePath;
final appDocDir = await getTemporaryDirectory();
@@ -375,6 +409,7 @@ class AttachmentActionsModal extends StatelessWidget {
onReceiveProgress: progressCallback,
);
final result = await ImageGallerySaver.saveFile(filePath!);
downloadedPathCallback?.call((result as Map)['filePath']);
return (result as Map)['filePath'];
}
}
@@ -388,6 +423,8 @@ class _DownloadProgress {
final int total;
final int received;
String get receivedValueInMB => ((received / 1024) / 1024).toStringAsFixed(2);
double get toProgressIndicatorValue => received / total;
int get toPercentage => (received * 100) ~/ total;
@@ -5,6 +5,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:chewie/chewie.dart';
import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';
import 'package:stream_chat_flutter/src/stream_attachment_package.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:video_player/video_player.dart';
@@ -32,8 +33,7 @@ class StreamFullScreenMedia extends StatefulWidget {
/// Instantiate a new FullScreenImage
const StreamFullScreenMedia({
Key? key,
required this.mediaAttachments,
required this.message,
required this.mediaAttachmentPackages,
this.startIndex = 0,
String? userName,
this.onShowMessage,
@@ -43,10 +43,7 @@ class StreamFullScreenMedia extends StatefulWidget {
super(key: key);
/// The url of the image
final List<Attachment> mediaAttachments;
/// Message where attachments are attached
final Message message;
final List<StreamAttachmentPackage> mediaAttachmentPackages;
/// First index of media shown
final int startIndex;
@@ -100,8 +97,8 @@ class _StreamFullScreenMediaState extends State<StreamFullScreenMedia>
duration: const Duration(milliseconds: 300),
);
_pageController = PageController(initialPage: widget.startIndex);
for (var i = 0; i < widget.mediaAttachments.length; i++) {
final attachment = widget.mediaAttachments[i];
for (var i = 0; i < widget.mediaAttachmentPackages.length; i++) {
final attachment = widget.mediaAttachmentPackages[i].attachment;
if (attachment.type != 'video') continue;
final package = VideoPackage(attachment, showControls: true);
videoPackages[attachment.id] = package;
@@ -114,7 +111,8 @@ class _StreamFullScreenMediaState extends State<StreamFullScreenMedia>
return;
}
final currentAttachment = widget.mediaAttachments[widget.startIndex];
final currentAttachment =
widget.mediaAttachmentPackages[widget.startIndex].attachment;
await Future.wait(videoPackages.values.map(
(it) => it.initialize(),
@@ -142,7 +140,8 @@ class _StreamFullScreenMediaState extends State<StreamFullScreenMedia>
return;
}
final currentAttachment = widget.mediaAttachments[val];
final currentAttachment =
widget.mediaAttachmentPackages[val].attachment;
for (final e in videoPackages.values) {
if (e._attachment != currentAttachment) {
@@ -157,7 +156,9 @@ class _StreamFullScreenMediaState extends State<StreamFullScreenMedia>
}
},
itemBuilder: (context, index) {
final attachment = widget.mediaAttachments[index];
final currentAttachmentPackage =
widget.mediaAttachmentPackages[index];
final attachment = currentAttachmentPackage.attachment;
if (attachment.type == 'image' || attachment.type == 'giphy') {
final imageUrl = attachment.imageUrl ??
attachment.assetUrl ??
@@ -174,7 +175,7 @@ class _StreamFullScreenMediaState extends State<StreamFullScreenMedia>
maxScale: PhotoViewComputedScale.covered,
minScale: PhotoViewComputedScale.contained,
heroAttributes: PhotoViewHeroAttributes(
tag: widget.mediaAttachments,
tag: widget.mediaAttachmentPackages,
),
backgroundDecoration: BoxDecoration(
color: ColorTween(
@@ -218,53 +219,66 @@ class _StreamFullScreenMediaState extends State<StreamFullScreenMedia>
}
return const SizedBox();
},
itemCount: widget.mediaAttachments.length,
itemCount: widget.mediaAttachmentPackages.length,
),
FadeTransition(
opacity: _opacityAnimation,
child: ValueListenableBuilder<int>(
valueListenable: _currentPage,
builder: (context, value, child) => Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
StreamGalleryHeader(
userName: widget.userName,
sentAt: context.translations.sentAtText(
date: widget.message.createdAt,
time: widget.message.createdAt,
),
onBackPressed: () {
Navigator.of(context).pop();
},
message: widget.message,
currentIndex: value,
onShowMessage: () {
widget.onShowMessage?.call(
widget.message,
StreamChannel.of(context).channel,
);
},
attachmentActionsModalBuilder:
widget.attachmentActionsModalBuilder,
),
if (!widget.message.isEphemeral)
StreamGalleryFooter(
currentPage: value,
totalPages: widget.mediaAttachments.length,
mediaAttachments: widget.mediaAttachments,
message: widget.message,
mediaSelectedCallBack: (val) {
_currentPage.value = val;
_pageController.animateToPage(
val,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
Navigator.pop(context);
builder: (context, value, child) {
final _currentAttachmentPackage =
widget.mediaAttachmentPackages[value];
final _currentMessage = _currentAttachmentPackage.message;
final _currentAttachment =
_currentAttachmentPackage.attachment;
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
StreamGalleryHeader(
userName: widget.userName,
sentAt: context.translations.sentAtText(
date: widget
.mediaAttachmentPackages[_currentPage.value]
.message
.createdAt,
time: widget
.mediaAttachmentPackages[_currentPage.value]
.message
.createdAt,
),
onBackPressed: () {
Navigator.of(context).pop();
},
message: _currentMessage,
attachment: _currentAttachment,
onShowMessage: () {
widget.onShowMessage?.call(
_currentMessage,
StreamChannel.of(context).channel,
);
},
attachmentActionsModalBuilder:
widget.attachmentActionsModalBuilder,
),
],
),
if (!_currentMessage.isEphemeral)
StreamGalleryFooter(
currentPage: value,
totalPages: widget.mediaAttachmentPackages.length,
mediaAttachmentPackages:
widget.mediaAttachmentPackages,
mediaSelectedCallBack: (val) {
_currentPage.value = val;
_pageController.animateToPage(
val,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
Navigator.pop(context);
},
),
],
);
},
),
),
],
@@ -18,16 +18,15 @@ typedef GalleryFooter = StreamGalleryFooter;
/// {@endtemplate}
class StreamGalleryFooter extends StatefulWidget
implements PreferredSizeWidget {
/// Creates a channel header
/// Creates a StreamGalleryFooter
const StreamGalleryFooter({
Key? key,
required this.message,
this.onBackPressed,
this.onTitleTap,
this.onImageTap,
this.currentPage = 0,
this.totalPages = 0,
this.mediaAttachments = const [],
required this.mediaAttachmentPackages,
this.mediaSelectedCallBack,
this.backgroundColor,
}) : preferredSize = const Size.fromHeight(kToolbarHeight),
@@ -50,10 +49,7 @@ class StreamGalleryFooter extends StatefulWidget
final int totalPages;
/// All attachments to show
final List<Attachment> mediaAttachments;
/// Message which attachments are attached to
final Message message;
final List<StreamAttachmentPackage> mediaAttachmentPackages;
/// Callback when media is selected
final ValueChanged<int>? mediaSelectedCallBack;
@@ -99,8 +95,8 @@ class _StreamGalleryFooterState extends State<StreamGalleryFooter> {
color: galleryFooterThemeData.shareIconColor,
),
onPressed: () async {
final attachment =
widget.mediaAttachments[widget.currentPage];
final attachment = widget
.mediaAttachmentPackages[widget.currentPage].attachment;
final url = attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl!;
@@ -171,7 +167,7 @@ class _StreamGalleryFooterState extends State<StreamGalleryFooter> {
builder: (context) {
const crossAxisCount = 3;
final noOfRowToShowInitially =
widget.mediaAttachments.length > crossAxisCount ? 2 : 1;
widget.mediaAttachmentPackages.length > crossAxisCount ? 2 : 1;
final size = MediaQuery.of(context).size;
final initialChildSize =
48 + (size.width * noOfRowToShowInitially) / crossAxisCount;
@@ -212,7 +208,7 @@ class _StreamGalleryFooterState extends State<StreamGalleryFooter> {
child: GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: widget.mediaAttachments.length,
itemCount: widget.mediaAttachmentPackages.length,
padding: const EdgeInsets.all(1),
// ignore: lines_longer_than_80_chars
gridDelegate:
@@ -223,7 +219,10 @@ class _StreamGalleryFooterState extends State<StreamGalleryFooter> {
),
itemBuilder: (context, index) {
Widget media;
final attachment = widget.mediaAttachments[index];
final attachmentPackage =
widget.mediaAttachmentPackages[index];
final attachment = attachmentPackage.attachment;
final message = attachmentPackage.message;
if (attachment.type == 'video') {
media = InkWell(
onTap: () => widget.mediaSelectedCallBack!(index),
@@ -253,7 +252,7 @@ class _StreamGalleryFooterState extends State<StreamGalleryFooter> {
return Stack(
children: [
media,
if (widget.message.user != null)
if (message.user != null)
Padding(
padding: const EdgeInsets.all(8),
child: Container(
@@ -272,7 +271,7 @@ class _StreamGalleryFooterState extends State<StreamGalleryFooter> {
],
),
child: StreamUserAvatar(
user: widget.message.user!,
user: message.user!,
constraints:
BoxConstraints.tight(const Size(24, 24)),
showOnlineStatus: false,
@@ -28,7 +28,7 @@ class StreamGalleryHeader extends StatelessWidget
const StreamGalleryHeader({
Key? key,
required this.message,
this.currentIndex = 0,
required this.attachment,
this.showBackButton = true,
this.onBackPressed,
this.onShowMessage,
@@ -60,15 +60,15 @@ class StreamGalleryHeader extends StatelessWidget
/// Message which attachments are attached to
final Message message;
/// The attachment that's currently in focus
final Attachment attachment;
/// Username of sender
final String userName;
/// Text which connotes the time the message was sent
final String sentAt;
/// Stores the current index of media shown
final int currentIndex;
/// The background color of this [StreamGalleryHeader].
final Color? backgroundColor;
@@ -146,14 +146,14 @@ class StreamGalleryHeader extends StatelessWidget
StreamChatTheme.of(context).galleryHeaderTheme;
final defaultModal = AttachmentActionsModal(
attachment: attachment,
message: message,
currentIndex: currentIndex,
onShowMessage: onShowMessage,
);
final effectiveModal = attachmentActionsModalBuilder?.call(
context,
message.attachments[currentIndex],
attachment,
defaultModal,
) ??
defaultModal;
@@ -136,10 +136,9 @@ class StreamImageGroup extends StatelessWidget {
builder: (context) => StreamChannel(
channel: channel,
child: StreamFullScreenMedia(
mediaAttachments: images,
mediaAttachmentPackages: message.getAttachmentPackageList(),
startIndex: index,
userName: message.user?.name,
message: message,
onShowMessage: onShowMessage,
),
),
@@ -0,0 +1,18 @@
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// The [StreamAttachmentPackage] class is basically meant to wrap
/// individual attachments with their corresponding message
class StreamAttachmentPackage {
/// Default constructor to prepare an [StreamAttachmentPackage] object
StreamAttachmentPackage({
required this.attachment,
required this.message,
});
/// This is the individual attachment
final Attachment attachment;
/// This is the message that the attachment belongs to
/// The message object may have attachemnt(s) other than the one packaged
final Message message;
}
@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/stream_attachment_package.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -429,3 +430,19 @@ int levenshtein(String s, String t, {bool caseSensitive = true}) {
return v1[t.length];
}
/// An easy way to handle attachment related operations on a message
extension AttachmentPackagesX on Message {
/// This extension will return a List of type [StreamAttachmentPackage] from the
/// existing attachments of the message
List<StreamAttachmentPackage> getAttachmentPackageList() {
final _attachmentPackages = List<StreamAttachmentPackage>.generate(
attachments.length,
(index) => StreamAttachmentPackage(
attachment: attachments[index],
message: this,
),
);
return _attachmentPackages;
}
}
@@ -28,10 +28,12 @@ export 'src/message_search_item.dart';
export 'src/message_search_list_view.dart';
export 'src/message_text.dart';
export 'src/message_widget.dart';
export 'src/multi_overlay.dart';
export 'src/option_list_tile.dart';
export 'src/reaction_icon.dart';
export 'src/reaction_picker.dart';
export 'src/sending_indicator.dart';
export 'src/stream_attachment_package.dart';
export 'src/stream_chat.dart';
export 'src/stream_chat_theme.dart';
export 'src/stream_neumorphic_button.dart';
+1 -1
View File
@@ -15,7 +15,7 @@ dependencies:
chewie: ^1.3.0
collection: ^1.15.0
diacritic: ^0.1.3
dio: ^4.0.0
dio: ^4.0.6
ezanimation: ^0.6.0
file_picker: ^4.1.3
flutter:
@@ -9,13 +9,16 @@ import 'mocks.dart';
class MockAttachmentDownloader extends Mock {
ProgressCallback? progressCallback;
DownloadedPathCallback? downloadedPathCallback;
Completer<String> completer = Completer();
Future<String> call(
Attachment attachment, {
ProgressCallback? progressCallback,
DownloadedPathCallback? downloadedPathCallback,
}) {
this.progressCallback = progressCallback;
this.downloadedPathCallback = downloadedPathCallback;
return completer.future;
}
}
@@ -38,6 +41,19 @@ void main() {
final themeData = ThemeData();
final streamTheme = StreamChatThemeData.fromTheme(themeData);
final attachment = Attachment(
type: 'image',
title: 'text.jpg',
);
final message = Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
attachment,
],
);
await tester.pumpWidget(
MaterialApp(
theme: themeData,
@@ -45,19 +61,8 @@ void main() {
streamChatThemeData: streamTheme,
client: client,
child: AttachmentActionsModal(
message: Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'image',
title: 'text.jpg',
),
],
),
currentIndex: 0,
message: message,
attachment: attachment,
),
),
),
@@ -80,6 +85,19 @@ void main() {
final themeData = ThemeData();
final streamTheme = StreamChatThemeData.fromTheme(themeData);
final attachment = Attachment(
type: 'image',
title: 'text.jpg',
);
final message = Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
attachment,
],
);
await tester.pumpWidget(
MaterialApp(
theme: themeData,
@@ -87,19 +105,8 @@ void main() {
streamChatThemeData: streamTheme,
client: client,
child: AttachmentActionsModal(
message: Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'image',
title: 'text.jpg',
),
],
),
currentIndex: 0,
message: message,
attachment: attachment,
),
),
),
@@ -122,6 +129,19 @@ void main() {
final themeData = ThemeData();
final streamTheme = StreamChatThemeData.fromTheme(themeData);
final attachment = Attachment(
type: 'video',
title: 'video.mp4',
);
final message = Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
attachment,
],
);
await tester.pumpWidget(
MaterialApp(
theme: themeData,
@@ -130,19 +150,8 @@ void main() {
client: client,
child: SizedBox(
child: AttachmentActionsModal(
message: Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'video',
title: 'video.mp4',
),
],
),
currentIndex: 0,
message: message,
attachment: attachment,
),
),
),
@@ -166,16 +175,17 @@ void main() {
final mockObserver = MockNavigatorObserver();
final attachment = Attachment(
type: 'image',
title: 'image.jpg',
);
final message = Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'image',
title: 'image.jpg',
),
attachment,
],
);
await tester.pumpWidget(
@@ -188,7 +198,7 @@ void main() {
child: SizedBox(
child: AttachmentActionsModal(
message: message,
currentIndex: 0,
attachment: attachment,
),
),
),
@@ -212,6 +222,20 @@ void main() {
final streamTheme = StreamChatThemeData.fromTheme(themeData);
final onShowMessage = MockVoidCallback();
final attachment = Attachment(
type: 'image',
title: 'image.jpg',
);
final message = Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
attachment,
],
);
await tester.pumpWidget(
MaterialApp(
theme: themeData,
@@ -221,18 +245,8 @@ void main() {
child: SizedBox(
child: AttachmentActionsModal(
onShowMessage: onShowMessage,
message: Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'image',
title: 'image.jpg',
),
]),
currentIndex: 0,
message: message,
attachment: attachment,
),
),
),
@@ -255,20 +269,22 @@ void main() {
when(() => client.state).thenReturn(clientState);
when(() => clientState.currentUser).thenReturn(OwnUser(id: 'user-id'));
final targetAttachment = Attachment(
type: 'image',
title: 'image.jpg',
);
final remainingAttachment = Attachment(
type: 'image',
title: 'image.jpg',
);
final message = Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'image',
title: 'image.jpg',
),
Attachment(
type: 'image',
title: 'image.jpg',
),
targetAttachment,
remainingAttachment,
],
);
@@ -283,7 +299,7 @@ void main() {
channel: mockChannel,
child: AttachmentActionsModal(
message: message,
currentIndex: 0,
attachment: targetAttachment,
),
),
),
@@ -309,16 +325,17 @@ void main() {
when(() => client.state).thenReturn(clientState);
when(() => clientState.currentUser).thenReturn(OwnUser(id: 'user-id'));
final attachment = Attachment(
type: 'image',
title: 'image.jpg',
);
final message = Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'image',
title: 'image.jpg',
),
attachment,
],
);
@@ -333,7 +350,7 @@ void main() {
channel: mockChannel,
child: AttachmentActionsModal(
message: message,
currentIndex: 0,
attachment: attachment,
),
),
),
@@ -358,15 +375,16 @@ void main() {
when(() => client.state).thenReturn(clientState);
when(() => clientState.currentUser).thenReturn(OwnUser(id: 'user-id'));
final attachment = Attachment(
type: 'image',
title: 'image.jpg',
);
final message = Message(
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'image',
title: 'image.jpg',
),
attachment,
],
);
@@ -381,7 +399,7 @@ void main() {
channel: mockChannel,
child: AttachmentActionsModal(
message: message,
currentIndex: 0,
attachment: attachment,
),
),
),
@@ -402,6 +420,20 @@ void main() {
final imageDownloader = MockAttachmentDownloader();
final attachment = Attachment(
type: 'image',
title: 'image.jpg',
);
final message = Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
attachment,
],
);
await tester.pumpWidget(
MaterialApp(
builder: (context, child) => StreamChat(
@@ -411,18 +443,8 @@ void main() {
home: SizedBox(
child: AttachmentActionsModal(
imageDownloader: imageDownloader,
message: Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'image',
title: 'image.jpg',
),
]),
currentIndex: 0,
message: message,
attachment: attachment,
),
),
),
@@ -457,6 +479,19 @@ void main() {
final fileDownloader = MockAttachmentDownloader();
final attachment = Attachment(
type: 'video',
title: 'video.mp4',
);
final message = Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
attachment,
]);
await tester.pumpWidget(
MaterialApp(
builder: (context, child) => StreamChat(
@@ -466,18 +501,8 @@ void main() {
home: SizedBox(
child: AttachmentActionsModal(
fileDownloader: fileDownloader,
message: Message(
text: 'test',
user: User(
id: 'user-id',
),
attachments: [
Attachment(
type: 'video',
title: 'video.mp4',
),
]),
currentIndex: 0,
message: message,
attachment: attachment,
),
),
),
@@ -63,22 +63,29 @@ void main() {
Event(type: EventType.typingStart),
}));
final attachment = Attachment(
type: 'image',
title: 'demo image',
imageUrl: '',
);
final message = Message(
createdAt: DateTime.now(),
attachments: [
attachment,
],
);
await tester.pumpWidget(MaterialApp(
home: StreamChat(
client: client,
child: StreamChannel(
channel: channel,
child: StreamFullScreenMedia(
mediaAttachments: [
Attachment(
type: 'image',
title: 'demo image',
imageUrl: '',
mediaAttachmentPackages: [
StreamAttachmentPackage(
attachment: attachment,
message: message,
),
],
message: Message(
createdAt: DateTime.now(),
),
),
),
),
@@ -38,7 +38,7 @@ void main() {
onWillPop: () async => false,
child: Scaffold(
body: StreamGalleryFooter(
message: Message(),
mediaAttachmentPackages: Message().getAttachmentPackageList(),
),
),
),
@@ -75,7 +75,7 @@ void main() {
_context = context;
return Scaffold(
appBar: StreamGalleryFooter(
message: Message(),
mediaAttachmentPackages: Message().getAttachmentPackageList(),
),
);
},
@@ -118,7 +118,7 @@ void main() {
_context = context;
return Scaffold(
appBar: StreamGalleryFooter(
message: Message(),
mediaAttachmentPackages: Message().getAttachmentPackageList(),
),
);
},
@@ -66,9 +66,11 @@ void main() {
home: Builder(
builder: (context) {
_context = context;
final _message = Message();
return Scaffold(
appBar: StreamGalleryHeader(
message: Message(),
message: _message,
attachment: _message.attachments[0],
),
);
},
@@ -105,9 +107,11 @@ void main() {
home: Builder(
builder: (context) {
_context = context;
final _message = Message();
return Scaffold(
appBar: StreamGalleryHeader(
message: Message(),
message: _message,
attachment: _message.attachments[0],
),
);
},