Merge pull request #689 from GetStream/ref/add-attachment-additional-fields
feat(llc): add `fileSize`, `mimeType` in Attachment model
This commit is contained in:
@@ -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');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user