diff --git a/lib/utils/client_download_content_extension.dart b/lib/utils/client_download_content_extension.dart index 65e7e023c..3da8a1c51 100644 --- a/lib/utils/client_download_content_extension.dart +++ b/lib/utils/client_download_content_extension.dart @@ -1,6 +1,7 @@ +import 'dart:math' show min; import 'dart:typed_data'; +import 'dart:ui'; -import 'package:image/image.dart'; import 'package:matrix/matrix.dart'; extension ClientDownloadContentExtension on Client { @@ -49,10 +50,10 @@ extension ClientDownloadContentExtension on Client { var imageData = response.bodyBytes; if (rounded) { - final image = decodeImage(imageData); - if (image != null) { - imageData = encodePng(copyCropCircle(image)); - } + imageData = await _convertToCircularImage( + imageData, + min(width ?? 64, height ?? 64).round(), + ); } await database.storeFile(cacheKey, imageData, 0); @@ -60,3 +61,43 @@ extension ClientDownloadContentExtension on Client { return imageData; } } + +Future _convertToCircularImage( + Uint8List imageBytes, + int size, +) async { + final codec = await instantiateImageCodec(imageBytes); + final frame = await codec.getNextFrame(); + final originalImage = frame.image; + + final recorder = PictureRecorder(); + final canvas = Canvas(recorder); + + final paint = Paint(); + final rect = Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble()); + + final clipPath = Path() + ..addOval( + Rect.fromCircle(center: Offset(size / 2, size / 2), radius: size / 2), + ); + + canvas.clipPath(clipPath); + + canvas.drawImageRect( + originalImage, + Rect.fromLTWH( + 0, + 0, + originalImage.width.toDouble(), + originalImage.height.toDouble(), + ), + rect, + paint, + ); + + final picture = recorder.endRecording(); + final circularImage = await picture.toImage(size, size); + + final byteData = await circularImage.toByteData(format: ImageByteFormat.png); + return byteData!.buffer.asUint8List(); +} diff --git a/lib/widgets/local_notifications_extension.dart b/lib/widgets/local_notifications_extension.dart index 30664a1fe..3036a92d2 100644 --- a/lib/widgets/local_notifications_extension.dart +++ b/lib/widgets/local_notifications_extension.dart @@ -55,7 +55,7 @@ extension LocalNotificationsExtension on MatrixState { Uri? thumbnailUri; if (avatarUrl != null) { - const size = 64; + const size = 128; const thumbnailMethod = ThumbnailMethod.crop; // Pre-cache so that we can later just set the thumbnail uri as icon: await client.downloadMxcCached( @@ -64,6 +64,7 @@ extension LocalNotificationsExtension on MatrixState { height: size, thumbnailMethod: thumbnailMethod, isThumbnail: true, + rounded: true, ); thumbnailUri = @@ -100,6 +101,7 @@ extension LocalNotificationsExtension on MatrixState { height: size, thumbnailMethod: thumbnailMethod, isThumbnail: true, + rounded: true, ); final image = decodeImage(data); diff --git a/scripts/release-ios-testflight.sh b/scripts/release-ios-testflight.sh index 22ab6f382..f34f6c826 100644 --- a/scripts/release-ios-testflight.sh +++ b/scripts/release-ios-testflight.sh @@ -1,5 +1,6 @@ #!/bin/sh -ve -./scripts/add-firebase-messaging.sh +flutter pub add fcm_shared_isolate:0.1.0 +sed -i '' 's,//,,g' lib/utils/background_push.dart yq eval '.dependencies.fcm_shared_isolate = "0.1.0"' -i pubspec.yaml # Workaround: 0.2.0 does not work on iOS flutter clean flutter pub get