Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ export 'package:mineral/src/api/common/commands/command_option_type.dart';
export 'package:mineral/src/api/common/commands/command_type.dart';
export 'package:mineral/src/api/common/components/component.dart';
export 'package:mineral/src/api/common/components/component_type.dart';
export 'package:mineral/src/api/common/components/message/message_button.dart';
export 'package:mineral/src/api/common/components/media_item.dart';
// Commons
export 'package:mineral/src/api/common/components/message/message_builder.dart';
export 'package:mineral/src/api/common/components/message/message_button.dart';
export 'package:mineral/src/api/common/components/message/message_file.dart';
export 'package:mineral/src/api/common/components/message/message_gallery.dart';
export 'package:mineral/src/api/common/components/message/message_media.dart';
export 'package:mineral/src/api/common/components/message/message_row_builder.dart';
export 'package:mineral/src/api/common/components/message/message_section.dart';
export 'package:mineral/src/api/common/components/message/message_separator.dart';
Expand Down
53 changes: 53 additions & 0 deletions lib/src/api/common/components/media_item.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import 'dart:io';
import 'dart:typed_data';

final class MediaItem {
Uint8List? bytes;
final String url;
bool? spoiler;
final String? proxyUrl;
final int? height;
final int? width;
final String? contentType;
final String? description;

MediaItem(this.url, {this.spoiler, this.proxyUrl, this.height, this.width, this.contentType, this.description});

factory MediaItem.file(File file, String name, {bool? spoiler, String? proxyUrl, int? height, int? width, String? contentType, String? description}) {
if (!file.existsSync()) {
throw ArgumentError('File ${file.path} does not exist');
}

if (name.isEmpty) {
throw ArgumentError("Name can't be empty.");
}

final bytes = file.readAsBytesSync();

return MediaItem(
'attachment://$name',
spoiler: spoiler,
proxyUrl: proxyUrl,
height: height,
width: width,
contentType: contentType,
description: description,
)..bytes = bytes;
}

Map<String, dynamic> toJson() {
return {
if (description != null) 'description': description,
'url': url,
if (bytes != null) 'bytes': bytes!,
if (spoiler != null) 'spoiler': spoiler,
'media': {
'url': url,
if (proxyUrl != null) 'proxy_url': proxyUrl,
if (height != null) 'height': height,
if (width != null) 'width': width,
if (contentType != null) 'content_type': contentType,
},
};
}
}
2 changes: 1 addition & 1 deletion lib/src/api/common/components/message/message_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ final class MessageBuilder {
_components.add(gallery);
}

void file(Attachment file) {
void file(MessageFile file) {
_components.add(file);
}

Expand Down
50 changes: 10 additions & 40 deletions lib/src/api/common/components/message/message_file.dart
Original file line number Diff line number Diff line change
@@ -1,56 +1,26 @@
import 'dart:io';
import 'dart:typed_data';

import 'package:http/http.dart' as http;
import 'package:mineral/api.dart';

final class Attachment implements Component {
final class MessageFile implements Component {
ComponentType get type => ComponentType.file;

static final Map<String, Uint8List> _cachedAttachments = {};

Uint8List? bytes;
final String _path;
final bool? _spoiler;

Attachment(this._path, {bool? spoiler}) : _spoiler = spoiler;

factory Attachment.path(String path, {bool? spoiler, bool cache = false}) {
if (cache && _cachedAttachments.containsKey(path)) {
return Attachment(path, spoiler: spoiler)
..bytes = _cachedAttachments[path]!;
}
MediaItem item;

final file = File(path);
final bytes = file.readAsBytesSync();

return Attachment(path, spoiler: spoiler)..bytes = bytes;
}

static Future<Attachment> network(String url,
{bool? spoiler, bool cache = false}) async {
if (cache && _cachedAttachments.containsKey(url)) {
return Attachment(url, spoiler: spoiler)
..bytes = _cachedAttachments[url]!;
}
MessageFile(this.item);

static Future<MessageFile> network(String url, {bool? spoiler}) async {
final uri = Uri.parse(url);
final response = await http.get(uri);
final name = uri.pathSegments.isNotEmpty ? uri.pathSegments.last : 'file.txt';
final media = MediaItem('attachment://$name')
..bytes = response.bodyBytes
..spoiler = spoiler;

_cachedAttachments[url] = response.bodyBytes;

return Attachment(uri.path, spoiler: spoiler)..bytes = response.bodyBytes;
return MessageFile(media);
}

@override
Map<String, dynamic> toJson() {
return {
'type': type.value,
'file': {
'url': _path,
'bytes': bytes,
},
if (_spoiler != null) 'spoiler': _spoiler,
};
return {'type': type.value, ...item.toJson()};
}
}
69 changes: 2 additions & 67 deletions lib/src/api/common/components/message/message_gallery.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:mineral/api.dart';

final class MessageGallery implements Component {
ComponentType get type => ComponentType.mediaGallery;
final List<GalleryItem> _items;
final List<MediaItem> _items;

MessageGallery({required List<GalleryItem> items}) : _items = items;
MessageGallery({required List<MediaItem> items}) : _items = items;

@override
Map<String, dynamic> toJson() {
Expand All @@ -16,66 +14,3 @@ final class MessageGallery implements Component {
};
}
}

final class GalleryItem {
final MessageMedia _media;
final String? _description;
final bool? _spoiler;
Uint8List? _bytes;

GalleryItem(
String url, {
String? proxyUrl,
int? height,
int? width,
String? contentType,
String? description,
bool? spoiler,
}) : _media = MessageMedia(
url,
proxyUrl: proxyUrl,
height: height,
width: width,
contentType: contentType,
),
_description = description,
_spoiler = spoiler;

Map<String, dynamic> toJson() {
return {
'media': {
'url': _media.url,
if (_media.proxyUrl != null) 'proxy_url': _media.proxyUrl,
if (_media.height != null) 'height': _media.height,
if (_media.width != null) 'width': _media.width,
if (_media.contentType != null) 'content_type': _media.contentType,
},
if (_bytes != null) 'bytes': _bytes!,
if (_description != null) 'description': _description,
if (_spoiler != null) 'spoiler': _spoiler,
};
}


/// ```dart
/// final file = File("assets/logo.png");
// final myImage = GalleryItem.fromFile(file, "test.png");
/// ```
///
/// WARN: Please make sure you put the correct file extension in the name.
/// Used to put a image file to discord's gallery instead of an url.
factory GalleryItem.fromFile(File file, String name) {
if (!file.existsSync()) {
throw ArgumentError('File ${file.path} does not exist');
}

if (name.isEmpty) {
throw ArgumentError("Name can't be empty.");
}

final bytes = file.readAsBytesSync();

return GalleryItem('attachment://$name')
.._bytes = bytes;
}
}
15 changes: 0 additions & 15 deletions lib/src/api/common/components/message/message_media.dart

This file was deleted.

23 changes: 3 additions & 20 deletions lib/src/api/common/components/message/message_thumbnail.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,15 @@ import 'package:mineral/api.dart';

final class MessageThumbnail implements Component {
ComponentType get type => ComponentType.thumbnail;
final MediaItem media;

final MessageMedia _media;
final String? _description;
final bool? _spoiler;

MessageThumbnail(
MessageMedia media, {
String? description,
bool? spoiler,
}) : _media = media,
_description = description,
_spoiler = spoiler;
MessageThumbnail(this.media);

@override
Map<String, dynamic> toJson() {
return {
'type': type.value,
'media': {
'url': _media.url,
if (_media.proxyUrl != null) 'proxy_url': _media.proxyUrl,
if (_media.height != null) 'height': _media.height,
if (_media.width != null) 'width': _media.width,
if (_media.contentType != null) 'content_type': _media.contentType,
},
if (_description != null) 'description': _description,
if (_spoiler != null) 'spoiler': _spoiler,
...media.toJson(),
};
}
}
68 changes: 37 additions & 31 deletions lib/src/domains/common/utils/attachment.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import 'package:http/http.dart' as http;
import 'package:mineral/api.dart';

typedef AttachmentResult = (
List<Map<String, dynamic>>,
List<http.MultipartFile>
);
typedef AttachmentResult = (List<Map<String, dynamic>>, List<http.MultipartFile>);

AttachmentResult makeAttachmentFromBuilder(MessageBuilder builder) {
final components = builder.build();
Expand All @@ -14,40 +11,23 @@ AttachmentResult makeAttachmentFromBuilder(MessageBuilder builder) {
final comp = components[i];

if (comp['type'] == ComponentType.file.value) {
final filePath = comp['file']['url'];
final filename = filePath.split('/').last;

final multipartFile = http.MultipartFile.fromBytes(
'files[${files.length}]',
comp['file']['bytes'],
filename: filename,
);

files.add(multipartFile);
comp['file']['url'] = 'attachment://$filename';
comp['file']['bytes'] = null;
final file = _prepareAsset(comp, files.length);

if (file != null) {
files.add(file);
}

continue;
}

if (comp['type'] == ComponentType.mediaGallery.value) {
final items = comp['items'] as List<dynamic>?;
if (items != null) {
for (final item in items) {
final media = item['media'] as Map<String, dynamic>?;
final url = media?['url'] as String?;

if (url != null && url.startsWith('attachment://') && item['bytes'] != null) {
final filename = url.replaceFirst('attachment://', '');
final bytes = item['bytes'];

if (bytes != null) {
final multipartFile = http.MultipartFile.fromBytes(
'files[${files.length}]',
bytes,
filename: filename,
);
files.add(multipartFile);
}
final file = _prepareAsset(item, files.length);

if (file != null) {
files.add(file);
}
}
}
Expand All @@ -56,3 +36,29 @@ AttachmentResult makeAttachmentFromBuilder(MessageBuilder builder) {

return (components, files);
}

http.MultipartFile? _prepareAsset(dynamic payload, int filesLength) {
final media = payload['media'] as Map<String, dynamic>?;
final url = media?['url'] as String?;

if (url != null && url.startsWith('attachment://') && payload['bytes'] != null) {
final filename = url.replaceFirst('attachment://', '');

final multipartFile = http.MultipartFile.fromBytes(
'files[$filesLength]',
payload['bytes'],
filename: filename,
);

payload['url'] = 'attachment://$filename';
payload['file'] = {
'url': 'attachment://$filename',
'name': filename,
};
payload['bytes'] = null;

return multipartFile;
}

return null;
}