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