Merge pull request #689 from GetStream/ref/add-attachment-additional-fields

feat(llc): add `fileSize`, `mimeType` in Attachment model
This commit is contained in:
Salvatore Giordano
2021-09-16 12:54:29 +02:00
committed by GitHub
4 changed files with 96 additions and 11 deletions
+3
View File
@@ -15,6 +15,9 @@
- Added `Filter.contains` and `Filter.empty`
- Added support for `next`, `previous` value pagination in `client.search`
, [read more.](https://getstream.io/chat/docs/other-rest/search/#pagination)
- `Attachment` class now has a `fileSize` and `mimeType` property. Setting a `file` will also set the `file_size`
, `mime_type` key on `extraData`, so `attachment.fileSize`, `attachment.mimetype` and `attachment.extraData['file_size']`
, `attachment.extraData['mime_type]` is same respectively.
🐞 Fixed
@@ -33,13 +33,20 @@ class Attachment extends Equatable {
this.authorIcon,
this.assetUrl,
List<Action>? actions,
this.extraData = const {},
Map<String, Object?> extraData = const {},
this.file,
UploadState? uploadState,
}) : id = id ?? const Uuid().v4(),
title = title ?? file?.name,
localUri = file?.path != null ? Uri.parse(file!.path!) : null,
actions = actions ?? [] {
actions = actions ?? [],
// For backwards compatibility,
// set 'file_size', 'mime_type' in [extraData].
extraData = {
...extraData,
if (file?.size != null) 'file_size': file?.size,
if (file?.mimeType != null) 'mime_type': file?.mimeType?.mimeType,
} {
this.uploadState = uploadState ??
((assetUrl != null || imageUrl != null)
? const UploadState.success()
@@ -121,6 +128,18 @@ class Attachment extends Equatable {
/// This is created locally for uniquely identifying a attachment.
final String id;
/// Shortcut for file size.
///
/// {@macro fileSize}
@JsonKey(ignore: true)
int? get fileSize => extraData['file_size'] as int?;
/// Shortcut for file mimeType.
///
/// {@macro mimeType}
@JsonKey(ignore: true)
String? get mimeType => extraData['mime_type'] as String?;
/// Known top level fields.
/// Useful for [Serializer] methods.
static const topLevelFields = [
@@ -2,6 +2,7 @@ import 'dart:typed_data';
import 'package:dio/dio.dart' show MultipartFile;
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:http_parser/http_parser.dart';
import 'package:meta/meta.dart';
import 'package:stream_chat/src/core/platform_detector/platform_detector.dart';
import 'package:stream_chat/src/core/util/extension.dart';
@@ -65,7 +66,7 @@ class AttachmentFile {
AttachmentFile({
required this.size,
this.path,
this.name,
String? name,
this.bytes,
}) : assert(
path != null || bytes != null,
@@ -74,7 +75,12 @@ class AttachmentFile {
assert(
!CurrentPlatform.isWeb || bytes != null,
'File by path is not supported in web, Please provide bytes',
);
),
assert(
name?.contains('.') ?? true,
'Invalid file name, should also contain file extension',
),
_name = name;
/// Create a new instance from a json
factory AttachmentFile.fromJson(Map<String, dynamic> json) =>
@@ -87,8 +93,10 @@ class AttachmentFile {
/// ```
final String? path;
final String? _name;
/// File name including its extension.
final String? name;
String? get name => _name ?? path?.split('/').last;
/// Byte data for this file. Particularly useful if you want to manipulate
/// its data or easily upload to somewhere else.
@@ -101,26 +109,26 @@ class AttachmentFile {
/// File extension for this file.
String? get extension => name?.split('.').last;
/// The mime type of this file.
MediaType? get mimeType => name?.mimeType;
/// Serialize to json
Map<String, dynamic> toJson() => _$AttachmentFileToJson(this);
/// Converts this into a [MultipartFile]
Future<MultipartFile> toMultipartFile() async {
final filename = path?.split('/').last ?? name;
final mimeType = filename?.mimeType;
late MultipartFile multiPartFile;
MultipartFile multiPartFile;
if (CurrentPlatform.isWeb) {
multiPartFile = MultipartFile.fromBytes(
bytes!,
filename: filename,
filename: name,
contentType: mimeType,
);
} else {
multiPartFile = await MultipartFile.fromFile(
path!,
filename: filename,
filename: name,
contentType: mimeType,
);
}
@@ -1,5 +1,6 @@
import 'package:stream_chat/src/core/models/action.dart';
import 'package:stream_chat/src/core/models/attachment.dart';
import 'package:stream_chat/src/core/models/attachment_file.dart';
import 'package:test/test.dart';
import '../../utils.dart';
@@ -41,5 +42,59 @@ void main() {
},
);
});
test('fileName, mimeType property and extraData manipulation', () {
final file = AttachmentFile(size: 3, path: 'myfolder/myfile.txt');
final attachment = Attachment(file: file);
expect(attachment.fileSize, 3);
expect(attachment.mimeType, 'text/plain');
expect(attachment.toJson(), {
'title': 'myfile.txt',
'actions': [],
'file_size': 3,
'mime_type': 'text/plain'
});
expect(Attachment.fromJson(attachment.toJson()).toJson(), {
'title': 'myfile.txt',
'actions': [],
'file_size': 3,
'mime_type': 'text/plain'
});
// Setting the size and mimeType using extraData should work fine
var newAttachment = Attachment(
extraData: const {
'file_size': 6,
'mime_type': 'application/pdf',
},
);
expect(newAttachment.extraData['file_size'], 6);
expect(newAttachment.extraData['mime_type'], 'application/pdf');
expect(newAttachment.fileSize, 6);
expect(newAttachment.mimeType, 'application/pdf');
// switching a new file should update size and mimeType
final fileTwo = AttachmentFile(size: 12, path: 'myfolder/fileTwo.pdf');
newAttachment = attachment.copyWith(file: fileTwo);
expect(newAttachment.extraData['file_size'], 12);
expect(newAttachment.extraData['mime_type'], 'application/pdf');
expect(newAttachment.fileSize, 12);
expect(newAttachment.mimeType, 'application/pdf');
// if file is available, should override size and mimeType.
final fileThree = AttachmentFile(size: 9, path: 'myfolder/fileThree.png');
newAttachment = attachment.copyWith(file: fileThree, extraData: {
'file_size': 88,
'mime_type': 'application/pdf',
});
expect(newAttachment.extraData['file_size'], 9);
expect(newAttachment.extraData['mime_type'], 'image/png');
expect(newAttachment.fileSize, 9);
expect(newAttachment.mimeType, 'image/png');
});
});
}