Skip to content

Commit

Permalink
TW-1162: copy multiple images in web from platform
Browse files Browse the repository at this point in the history
  • Loading branch information
sherlockvn authored and hoangdat committed Jan 5, 2024
1 parent d7a8271 commit 6834292
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 56 deletions.
8 changes: 6 additions & 2 deletions lib/pages/chat/input_bar/input_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class InputBar extends StatelessWidget with PasteImageMixin {
Key? key,
}) : super(key: key);

static const debounceDuration = Duration(milliseconds: 50);

static const debounceDurationTap = Duration(milliseconds: 100);

List<Map<String, String?>> getSuggestions(String text) {
if (controller!.selection.baseOffset !=
controller!.selection.extentOffset ||
Expand Down Expand Up @@ -340,7 +344,7 @@ class InputBar extends StatelessWidget with PasteImageMixin {
hideOnEmpty: true,
hideOnLoading: true,
hideOnSelect: false,
debounceDuration: const Duration(milliseconds: 50),
debounceDuration: debounceDuration,
autoFlipDirection: true,
scrollController: suggestionScrollController,
controller: controller,
Expand All @@ -361,7 +365,7 @@ class InputBar extends StatelessWidget with PasteImageMixin {
}
},
onTap: () async {
await Future.delayed(const Duration(milliseconds: 100));
await Future.delayed(debounceDurationTap);
FocusScope.of(context).requestFocus(focusNode);
},
onSubmitted: PlatformInfos.isMobile
Expand Down
38 changes: 11 additions & 27 deletions lib/presentation/mixins/paste_image_mixin.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import 'dart:typed_data';

import 'package:fluffychat/pages/chat/send_file_dialog.dart';
import 'package:fluffychat/presentation/model/clipboard/clipboard_image_info.dart';
import 'package:fluffychat/utils/clipboard.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/twake_snackbar.dart';
Expand All @@ -22,41 +19,28 @@ mixin PasteImageMixin {
Logs().e('PasteImageMixin::pasteImage(): not readable image format');
return;
}
Uint8List? imageData;
ClipboardImageInfo? imageClipboard;
List<MatrixFile?>? matrixFiles;
if (PlatformInfos.isWeb) {
imageData = await Clipboard.instance
.pasteImageUsingBytes(reader: clipboardReader);
} else {
imageClipboard = await Clipboard.instance.pasteImageUsingStream();
if (imageClipboard == null) {
TwakeSnackBar.show(context, L10n.of(context)!.pasteImageFailed);
return;
}
// FIXME: need to update the SendFileDialog to have FileInfo inside
// after update we can use stream to read files instead of convert into raw image data
final data = await imageClipboard.stream.toList();
imageData = Uint8List.fromList(
data.expand((Uint8List uint8List) => uint8List).toList(),
);
matrixFiles = await Clipboard.instance
.pasteImagesUsingBytes(reader: clipboardReader);
}
if (imageData == null || imageData.isEmpty) {
if (matrixFiles == null || matrixFiles.isEmpty) {
TwakeSnackBar.show(context, L10n.of(context)!.pasteImageFailed);
return;
}

final nonNullableFiles = matrixFiles
.where(
(matrixFile) => matrixFile != null,
)
.cast<MatrixFile>()
.toList();
await showDialog(
context: context,
useRootNavigator: PlatformInfos.isWeb,
builder: (context) {
return SendFileDialog(
room: room,
files: [
MatrixImageFile(
name: imageClipboard?.fileName ?? 'copied',
bytes: imageData,
),
],
files: nonNullableFiles,
);
},
);
Expand Down
74 changes: 47 additions & 27 deletions lib/utils/clipboard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,35 +87,55 @@ class Clipboard {
return c.future;
}

Future<Uint8List?>? pasteImageUsingBytes({ClipboardReader? reader}) async {
Future<List<MatrixFile?>>? pasteImagesUsingBytes({
ClipboardReader? reader,
}) async {
_reader = reader ?? await SystemClipboard.instance?.read();
final readableFormats = _reader!.getFormats(allImageFormatsSupported);
if (readableFormats.isEmpty != false &&
readableFormats.first is! SimpleFileFormat) {
return null;
}

final c = Completer<Uint8List?>();
final progress = _reader!.getFile(
readableFormats.first as SimpleFileFormat,
(file) async {
try {
final all = await file.readAll();
c.complete(all);
} catch (e) {
Logs().e('Clipboard::pasteImageUsingBytes(): $e');
c.completeError(e);
}
},
onError: (e) {
Logs().e('Clipboard::pasteImageUsingBytes(): $e');
c.completeError(e);
},
);
if (progress == null) {
c.complete(null);
}
return c.future;
final futures = _reader?.items
.map((item) {
final c = Completer<MatrixFile?>();
final readableFormats = item.getFormats(allImageFormatsSupported);
if (readableFormats.isEmpty != false &&
readableFormats.first is! SimpleFileFormat) {
return null;
}
final format = readableFormats.first as SimpleFileFormat;
final progress = item.getFile(
format,
(file) async {
try {
final data = await file.readAll();

c.complete(
MatrixFile(
name: file.fileName ?? 'copied',
bytes: data,
mimeType: format.mimeTypes?.first,
),
);
} catch (e) {
Logs().e('Clipboard::pasteImageUsingBytes(): $e');
c.completeError(e);
}
},
onError: (e) {
Logs().e('Clipboard::pasteImageUsingBytes(): $e');
c.completeError(e);
},
);
if (progress == null) {
c.complete(null);
}
return c.future;
})
.where((future) => future != null)
.cast<Future<MatrixFile?>>()
.toList();

final results = await Future.wait<MatrixFile?>(futures ?? []);

return results;
}

Future<bool> isReadableImageFormat({ClipboardReader? clipboardReader}) async {
Expand Down

0 comments on commit 6834292

Please sign in to comment.