Implemented StreamAttachmentPackage and fixed operations in widgets linked to full screen implementation, also fixed tests
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user