From 7465cfadef16da0827e82276f9da793ae7f97380 Mon Sep 17 00:00:00 2001 From: MinhDV Date: Wed, 27 Sep 2023 21:47:32 +0700 Subject: [PATCH] TW-688 Web avoid frezze when uploading file --- .../extensions/send_file_web_extension.dart | 49 ++++++++++++++----- lib/utils/js_window/js_window.dart | 28 +++++++++++ lib/utils/js_window/non_js_window.dart | 7 +++ .../js_window/universal_image_bitmap.dart | 8 +++ pubspec.lock | 2 +- pubspec.yaml | 1 + 6 files changed, 81 insertions(+), 14 deletions(-) create mode 100644 lib/utils/js_window/js_window.dart create mode 100644 lib/utils/js_window/non_js_window.dart create mode 100644 lib/utils/js_window/universal_image_bitmap.dart diff --git a/lib/presentation/extensions/send_file_web_extension.dart b/lib/presentation/extensions/send_file_web_extension.dart index 5f81845bf9..c9f151a52d 100644 --- a/lib/presentation/extensions/send_file_web_extension.dart +++ b/lib/presentation/extensions/send_file_web_extension.dart @@ -1,6 +1,10 @@ +import 'dart:typed_data'; import 'package:blurhash_dart/blurhash_dart.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/utils/extension/web_url_creation_extension.dart'; +import 'package:fluffychat/utils/js_window/non_js_window.dart' + if (dart.library.js) 'package:fluffychat/utils/js_window/js_window.dart'; +import 'package:fluffychat/utils/js_window/universal_image_bitmap.dart'; import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:matrix/matrix.dart'; import 'package:image/image.dart'; @@ -19,20 +23,22 @@ extension SendFileWebExtension on Room { Map? extraContent, }) async { txid ??= client.generateUniqueTransactionId(); - Image? img; + UniversalImageBitmap? imageBitmap; if (file.bytes != null && file is MatrixImageFile) { - img = decodeImage(file.bytes!); + final stopwatch = Stopwatch()..start(); + imageBitmap = await convertUint8ListToBitmap(file.bytes!); + Logs().v('ImageBitmap creation took ${stopwatch.elapsed}'); file = MatrixImageFile( name: file.name, - width: img?.width, - height: img?.height, + width: imageBitmap?.width, + height: imageBitmap?.height, bytes: file.bytes, ); } sendingFilePlaceholders[txid] = MatrixImageFile( name: file.name, - width: img?.width, - height: img?.height, + width: imageBitmap?.width, + height: imageBitmap?.height, bytes: file.bytes, ); fakeImageEvent ??= await sendFakeImageEvent( @@ -262,11 +268,10 @@ extension SendFileWebExtension on Room { try { final result = await FlutterImageCompress.compressWithList( originalFile.bytes!, - quality: 70, + quality: AppConfig.thumbnailQuality, ); - final image = decodeImage(result); - final blurHash = image != null ? BlurHash.encode(image) : null; + final blurHash = await _generateBlurHash(result); return MatrixImageFile( bytes: result, @@ -274,7 +279,7 @@ extension SendFileWebExtension on Room { mimeType: originalFile.mimeType, width: originalFile.width, height: originalFile.height, - blurhash: blurHash?.hash, + blurhash: blurHash, ); } catch (e) { Logs().e('Error while generating thumbnail', e); @@ -296,8 +301,7 @@ extension SendFileWebExtension on Room { imageFormat: ImageFormat.JPEG, quality: AppConfig.thumbnailQuality, ); - final image = decodeImage(result); - final blurHash = image != null ? BlurHash.encode(image) : null; + final blurHash = await _generateBlurHash(result); return MatrixImageFile( bytes: result, @@ -305,7 +309,7 @@ extension SendFileWebExtension on Room { mimeType: originalFile.mimeType, width: originalFile.width, height: originalFile.height, - blurhash: blurHash?.hash, + blurhash: blurHash, ); } catch (e) { Logs().e('Error while generating thumbnail', e); @@ -334,3 +338,22 @@ extension SendFileWebExtension on Room { } } } + +Future _generateBlurHash(Uint8List data) async { + try { + final stopwatch = Stopwatch()..start(); + final result = await FlutterImageCompress.compressWithList( + data, + minHeight: AppConfig.blurHashSize, + minWidth: AppConfig.blurHashSize, + ); + Logs().v('_generateBlurHash::compress ${stopwatch.elapsed}'); + final image = decodeJpg(result); + final blurHash = image != null ? BlurHash.encode(image) : null; + Logs().v('_generateBlurHash::encode ${stopwatch.elapsed}'); + return blurHash?.hash; + } catch (e) { + Logs().e('_generateBlurHash::error', e); + return null; + } +} diff --git a/lib/utils/js_window/js_window.dart b/lib/utils/js_window/js_window.dart new file mode 100644 index 0000000000..0438353c89 --- /dev/null +++ b/lib/utils/js_window/js_window.dart @@ -0,0 +1,28 @@ +@JS() +library window; + +import 'package:fluffychat/utils/js_window/universal_image_bitmap.dart'; +import 'package:universal_html/html.dart'; +import 'dart:typed_data'; + +import 'package:js/js.dart'; +import 'package:js/js_util.dart'; + +@JS() +@staticInterop +class JSWindow {} + +extension JSWindowExtension on JSWindow { + external Function get createImageBitmap; +} + +JSWindow get jsWindow => window as JSWindow; + +Future convertUint8ListToBitmap(Uint8List buffer) async { + final blob = Blob([buffer]); + + final result = await jsWindow.createImageBitmap(blob); + final ImageBitmap bitmap = await promiseToFuture(result); + + return UniversalImageBitmap(width: bitmap.width, height: bitmap.height); +} diff --git a/lib/utils/js_window/non_js_window.dart b/lib/utils/js_window/non_js_window.dart new file mode 100644 index 0000000000..dd64f1d8b9 --- /dev/null +++ b/lib/utils/js_window/non_js_window.dart @@ -0,0 +1,7 @@ +import 'dart:typed_data'; + +import 'package:fluffychat/utils/js_window/universal_image_bitmap.dart'; + +Future convertUint8ListToBitmap(Uint8List buffer) async { + return null; +} diff --git a/lib/utils/js_window/universal_image_bitmap.dart b/lib/utils/js_window/universal_image_bitmap.dart new file mode 100644 index 0000000000..eac77c2058 --- /dev/null +++ b/lib/utils/js_window/universal_image_bitmap.dart @@ -0,0 +1,8 @@ +class UniversalImageBitmap { + int? height; + int? width; + UniversalImageBitmap({ + this.height, + this.width, + }); +} diff --git a/pubspec.lock b/pubspec.lock index d38eb3ac8f..70185da2f0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1376,7 +1376,7 @@ packages: source: hosted version: "2.1.1" js: - dependency: transitive + dependency: "direct main" description: name: js sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 diff --git a/pubspec.yaml b/pubspec.yaml index d5b379e163..cb0103bf55 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -149,6 +149,7 @@ dependencies: media_kit_video: ^1.1.8 media_kit_libs_video: ^1.0.1 video_player: ^2.7.2 + js: ^0.6.7 dev_dependencies: build_runner: ^2.3.3 dart_code_metrics: ^5.7.3