Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve file sending flow #285

Merged
merged 6 commits into from
Jun 27, 2024
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
21 changes: 21 additions & 0 deletions commet/lib/cache/file_provider.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
import 'dart:io';

abstract class FileProvider {
Future<Uri?> resolve();

Future<void> save(String filepath);

String get fileIdentifier;
}

class SystemFileProvider implements FileProvider {
File file;

@override
String get fileIdentifier => file.path;

@override
Future<Uri?> resolve() async {
return file.uri;
}

@override
Future<void> save(String filepath) {
throw UnimplementedError();
}

SystemFileProvider(this.file);
}
19 changes: 18 additions & 1 deletion commet/lib/client/attachment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ class PendingFileAttachment {
String? mimeType;
int? size;

Uint8List? thumbnailFile;
String? thumbnailMime;
Size? dimensions;
Duration? length;

PendingFileAttachment(
{this.name, this.path, this.data, this.mimeType, this.size}) {
assert(path != null || data != null);

mimeType ??= Mime.lookupType(path ?? "", data: data);
mimeType ??= Mime.lookupType(path ?? name ?? "", data: data);
}

Future<void> resolve() async {
Expand All @@ -38,6 +43,18 @@ class PendingFileAttachment {
}
}
}

ImageProvider? getAsImage() {
if (Mime.imageTypes.contains(mimeType)) {
if (data != null) {
return Image.memory(data!).image;
} else {
return Image.file(File(path!)).image;
}
}

return null;
}
}

class ImageAttachment implements Attachment {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ pQIDAQAB

var type = response["og:image:type"] as String?;
if (type != null) {
if (Mime.displayableTypes.contains(type) == false) {
if (Mime.displayableImageTypes.contains(type) == false) {
imageUrl = null;
}
}
Expand Down
12 changes: 10 additions & 2 deletions commet/lib/client/matrix/extensions/matrix_event_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,17 @@ extension MatrixExtensions on Event {
if (info == null) return null;

var path = info.tryGet("thumbnail_url") as String?;
if (path == null) return null;
if (path != null) {
return Uri.parse(path);
}

return Uri.parse(path);
var file = info.tryGetMap<String, dynamic>("thumbnail_file");
var url = file?.tryGet<String>("url");
if (url != null) {
return Uri.parse(url);
}

return null;
}

double? _attachmentWidth() {
Expand Down
4 changes: 3 additions & 1 deletion commet/lib/client/matrix/matrix_attachment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ import 'package:matrix/matrix.dart';
class MatrixProcessedAttachment extends ProcessedAttachment {
MatrixFile file;

MatrixProcessedAttachment(this.file);
MatrixImageFile? thumbnailFile;

MatrixProcessedAttachment(this.file, {this.thumbnailFile});
}
7 changes: 6 additions & 1 deletion commet/lib/client/matrix/matrix_mxc_image_provider.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:commet/main.dart';
import 'package:commet/utils/mime.dart';
import 'package:matrix/matrix.dart';

import '../../utils/image/lod_image.dart';
Expand Down Expand Up @@ -48,7 +49,9 @@ class MatrixMxcImage extends LODImageProvider {
if (matrixEvent != null) {
var data =
await matrixEvent.downloadAndDecryptAttachment(getThumbnail: true);
bytes = data.bytes;
if (Mime.imageTypes.contains(data.mimeType)) {
bytes = data.bytes;
}
} else {
var response = await client.httpClient
.get(uri.getThumbnail(client, width: 90, height: 90));
Expand Down Expand Up @@ -80,9 +83,11 @@ class MatrixMxcImage extends LODImageProvider {
Uint8List? bytes;
if (matrixEvent != null) {
var data = await matrixEvent.downloadAndDecryptAttachment();

bytes = data.bytes;
} else {
var response = await client.httpClient.get(uri.getDownloadLink(client));

if (response.statusCode == 200) {
bytes = response.bodyBytes;
}
Expand Down
49 changes: 38 additions & 11 deletions commet/lib/client/matrix/matrix_room.dart
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,11 @@ class MatrixRoom extends Room {
Future<List<ProcessedAttachment>> processAttachments(
List<PendingFileAttachment> attachments) async {
return await Future.wait(attachments.map((e) async {
var file = await processAttachment(e);
return MatrixProcessedAttachment(file!);
return (await processAttachment(e))!;
}));
}

Future<matrix.MatrixFile?> processAttachment(
Future<MatrixProcessedAttachment?> processAttachment(
PendingFileAttachment attachment) async {
await attachment.resolve();
if (attachment.data == null) return null;
Expand All @@ -300,13 +299,12 @@ class MatrixRoom extends Room {
try {
if (Mime.imageTypes.contains(attachment.mimeType)) {
await decodeImageFromList(attachment.data!);

return await matrix.MatrixImageFile.create(
return MatrixProcessedAttachment(await matrix.MatrixImageFile.create(
bytes: attachment.data!,
name: attachment.name ?? "unknown",
mimeType: attachment.mimeType,
nativeImplementations:
(client as MatrixClient).nativeImplentations);
(client as MatrixClient).nativeImplentations));
}
} catch (error, stack) {
// This image is probably corrupt, since it has a mime type we should be able to display,
Expand All @@ -315,10 +313,38 @@ class MatrixRoom extends Room {
Log.onError(error, stack);
}

return matrix.MatrixFile(
bytes: attachment.data!,
name: attachment.name ?? "Unknown",
mimeType: attachment.mimeType);
matrix.MatrixImageFile? thumbnailImageFile;
if (attachment.thumbnailFile != null) {
var decodedImage = await decodeImageFromList(attachment.thumbnailFile!);

thumbnailImageFile = matrix.MatrixImageFile(
bytes: attachment.thumbnailFile!,
width: decodedImage.width,
height: decodedImage.height,
mimeType: attachment.thumbnailMime,
name: "thumbnail");
}

if (Mime.videoTypes.contains(attachment.mimeType)) {
return MatrixProcessedAttachment(
matrix.MatrixVideoFile(
bytes: attachment.data!,
name: attachment.name ?? "Unknown",
mimeType: attachment.mimeType,
width: attachment.dimensions?.width.toInt(),
height: attachment.dimensions?.height.toInt(),
duration: attachment.length?.inMilliseconds,
),
thumbnailFile: thumbnailImageFile,
);
}

return MatrixProcessedAttachment(
matrix.MatrixFile(
bytes: attachment.data!,
name: attachment.name ?? "Unknown",
mimeType: attachment.mimeType),
thumbnailFile: thumbnailImageFile);
}

@override
Expand All @@ -340,7 +366,8 @@ class MatrixRoom extends Room {
processedAttachments.whereType<MatrixProcessedAttachment>().map((e) {
return _matrixRoom.sendFileEvent(e.file,
threadLastEventId: threadLastEventId,
threadRootEventId: threadRootEventId);
threadRootEventId: threadRootEventId,
thumbnail: e.thumbnailFile);
}));
}

Expand Down
35 changes: 21 additions & 14 deletions commet/lib/client/matrix/matrix_timeline_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ class MatrixTimelineEvent implements TimelineEvent {
}

void parseAnyAttachments(matrix.Event matrixEvent, matrix.Client client) {
if (matrixEvent.status.isSending) return;

if (matrixEvent.hasAttachment) {
double? width = matrixEvent.attachmentWidth;
double? height = matrixEvent.attachmentHeight;
Expand All @@ -319,20 +321,25 @@ class MatrixTimelineEvent implements TimelineEvent {
name: matrixEvent.body,
height: height);
} else if (Mime.videoTypes.contains(matrixEvent.attachmentMimetype)) {
attachment = VideoAttachment(
MxcFileProvider(client, matrixEvent.attachmentMxcUrl!,
event: matrixEvent),
thumbnail: matrixEvent.videoThumbnailUrl != null
? MatrixMxcImage(matrixEvent.videoThumbnailUrl!, client,
blurhash: matrixEvent.attachmentBlurhash,
doFullres: false,
doThumbnail: true,
matrixEvent: matrixEvent)
: null,
name: matrixEvent.body,
width: width,
fileSize: matrixEvent.infoMap['size'] as int?,
height: height);
// Only load videos if the event has finished sending, otherwise
// matrix dart sdk gives us the video file when we ask for thumbnail
if (matrixEvent.status.isSending == false) {
attachment = VideoAttachment(
MxcFileProvider(client, matrixEvent.attachmentMxcUrl!,
event: matrixEvent),
thumbnail: matrixEvent.videoThumbnailUrl != null
? MatrixMxcImage(matrixEvent.videoThumbnailUrl!, client,
blurhash: matrixEvent.attachmentBlurhash,
doFullres: false,
autoLoadFullRes: false,
doThumbnail: true,
matrixEvent: matrixEvent)
: null,
name: matrixEvent.body,
width: width,
fileSize: matrixEvent.infoMap['size'] as int?,
height: height);
}
} else {
attachment = FileAttachment(
MxcFileProvider(client, matrixEvent.attachmentMxcUrl!,
Expand Down
17 changes: 10 additions & 7 deletions commet/lib/config/preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';

import 'package:commet/config/build_config.dart';
import 'package:commet/config/platform_utils.dart';
import 'package:commet/config/theme_config.dart';
import 'package:commet/main.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -104,13 +105,15 @@ class Preferences {
WidgetsBinding.instance.platformDispatcher.platformBrightness;
}

var custom = await ThemeConfig.getThemeByName(preferences.theme);
if (custom != null) {
var jsonString = await custom.readAsString();
var json = const JsonDecoder().convert(jsonString);
var themedata = await ThemeJsonConverter.fromJson(json, custom);
if (themedata != null) {
return themedata;
if (!PlatformUtils.isWeb) {
var custom = await ThemeConfig.getThemeByName(preferences.theme);
if (custom != null) {
var jsonString = await custom.readAsString();
var json = const JsonDecoder().convert(jsonString);
var themedata = await ThemeJsonConverter.fromJson(json, custom);
if (themedata != null) {
return themedata;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions commet/lib/ui/atoms/message_attachment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class _MessageAttachmentState extends State<MessageAttachment> {
attachment.videoFile,
thumbnail: attachment.thumbnail,
fileName: attachment.name,
doThumbnail: true,
canGoFullscreen: true,
onFullscreen: fullscreenVideo,
key: videoPlayerKey,
Expand Down
20 changes: 14 additions & 6 deletions commet/lib/ui/molecules/attachment_icon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,27 @@ class AttachmentIcon extends StatefulWidget {
class _AttachmentIconState extends State<AttachmentIcon> {
bool hovered = false;

@override
Widget build(BuildContext context) {
Image? image;
ImageProvider? image;

@override
void initState() {
if (Mime.imageTypes.contains(widget.attachment.mimeType) &&
widget.attachment.data != null) {
image = Image.memory(widget.attachment.data!,
filterQuality: FilterQuality.medium, fit: BoxFit.cover);
image = Image.memory(widget.attachment.data!).image;
}

if (widget.attachment.thumbnailFile != null) {
image = Image.memory(widget.attachment.thumbnailFile!).image;
}

super.initState();
}

@override
Widget build(BuildContext context) {
return ImageButton(
size: 20,
image: image?.image,
image: image,
icon: Mime.toIcon(widget.attachment.mimeType),
onTap: widget.removeAttachment,
iconSize: 20,
Expand Down
Loading
Loading