diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a4a4cd18..1bf0dc36 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -29,6 +29,10 @@ + 2.6.1) - image_gallery_saver (2.0.2): - Flutter - image_picker_ios (0.0.1): @@ -20,6 +23,7 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS + - TOCropViewController (2.6.1) - wakelock (0.0.1): - Flutter @@ -29,6 +33,7 @@ DEPENDENCIES: - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - flutter_tts (from `.symlinks/plugins/flutter_tts/ios`) - geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`) + - image_cropper (from `.symlinks/plugins/image_cropper/ios`) - image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) @@ -36,6 +41,10 @@ DEPENDENCIES: - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - wakelock (from `.symlinks/plugins/wakelock/ios`) +SPEC REPOS: + trunk: + - TOCropViewController + EXTERNAL SOURCES: Flutter: :path: Flutter @@ -47,6 +56,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_tts/ios" geolocator_apple: :path: ".symlinks/plugins/geolocator_apple/ios" + image_cropper: + :path: ".symlinks/plugins/image_cropper/ios" image_gallery_saver: :path: ".symlinks/plugins/image_gallery_saver/ios" image_picker_ios: @@ -66,11 +77,13 @@ SPEC CHECKSUMS: flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d geolocator_apple: 9157311f654584b9bb72686c55fc02a97b73f461 + image_cropper: a3291c624a953049bc6a02e1f8c8ceb162a24b25 image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425 path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 + TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863 wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f PODFILE CHECKSUM: 2442f0b84dc733c75ff32e76bcf04626a168288b diff --git a/lib/presentation/common/activity/widgets/activity_comments.dart b/lib/presentation/common/activity/widgets/activity_comments.dart index acdc1fcc..4ba4476b 100644 --- a/lib/presentation/common/activity/widgets/activity_comments.dart +++ b/lib/presentation/common/activity/widgets/activity_comments.dart @@ -22,13 +22,21 @@ class ActivityComments extends HookConsumerWidget { final GlobalKey formKey; final currentUserPictureDataProvider = - FutureProvider.family((ref, activity) async { + FutureProvider.family((ref, activity) async { final user = await StorageUtils.getUser(); final provider = ref.read(activityItemViewModelProvider(activity.id).notifier); user != null ? provider.getProfilePicture(user.id) : null; - return user?.id; + + if (user?.id != null) { + final profilePicture = + ref.watch(profilePictureViewModelProvider(user!.id)).profilePicture; + return profilePicture != null + ? MemoryImage(profilePicture) + : await ColorUtils.colorToImageProvider((Colors.white70)); + } + return await ColorUtils.colorToImageProvider(Colors.white70); }); final commentUserPictureDataProvider = @@ -90,7 +98,6 @@ class ActivityComments extends HookConsumerWidget { overflow: TextOverflow.visible, ), ), - const Spacer(), if (currentUser.id == comment.user.id) IconButton( color: ColorUtils.black, @@ -201,24 +208,14 @@ class ActivityComments extends HookConsumerWidget { height: state.comments.isNotEmpty ? 210 : 80, child: CommentBox( userImage: currentUserPictureProvider.when( - data: (userId) { - if (userId != null) { - final profilePicture = ref - .watch(profilePictureViewModelProvider(userId)) - .profilePicture; - return profilePicture != null - ? MemoryImage(profilePicture) - : null; - } - return null; - }, - loading: () => null, - error: (_, __) => null, - ), + data: (picture) { + return picture; + }, + loading: () => null, + error: (_, __) => null), sendButtonMethod: () => commentsProvider.comment(currentActivity), formKey: formKey, commentController: commentsProvider.commentController, - backgroundColor: ColorUtils.white, textColor: ColorUtils.mainMedium, sendWidget: Icon(Icons.send_sharp, size: 30, color: ColorUtils.main), diff --git a/lib/presentation/common/core/utils/color_utils.dart b/lib/presentation/common/core/utils/color_utils.dart index 0c7a6607..1db9d22c 100644 --- a/lib/presentation/common/core/utils/color_utils.dart +++ b/lib/presentation/common/core/utils/color_utils.dart @@ -1,3 +1,5 @@ +import 'dart:ui' as ui; + import 'package:flutter/material.dart'; /// Utility class for color-related operations. @@ -66,6 +68,22 @@ class ColorUtils { final lightColor = generateLightColor(baseColor); return [darkColor, lightColor]; } + + static Future?> colorToImageProvider(Color color, + {double width = 32.0, double height = 32.0}) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final paint = Paint()..color = color; + canvas.drawRect(Rect.fromLTRB(0, 0, width, height), paint); + final picture = recorder.endRecording(); + final img = await picture.toImage(width.toInt(), height.toInt()); + final byteData = await img.toByteData(format: ui.ImageByteFormat.png); + if (byteData != null) { + return MemoryImage(byteData.buffer.asUint8List()); + } else { + return null; + } + } } /// Extension methods for the [Color] class. diff --git a/lib/presentation/common/core/widgets/upload_file.dart b/lib/presentation/common/core/widgets/upload_file.dart index bb871346..d8b38bbb 100644 --- a/lib/presentation/common/core/widgets/upload_file.dart +++ b/lib/presentation/common/core/widgets/upload_file.dart @@ -3,10 +3,11 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:image_cropper/image_cropper.dart'; import 'package:image_picker/image_picker.dart'; -import '../utils/ui_utils.dart'; import '../utils/color_utils.dart'; +import '../utils/ui_utils.dart'; /// A widget that allow to upload a file class UploadFileWidget extends HookConsumerWidget { @@ -61,9 +62,32 @@ class UploadFileWidget extends HookConsumerWidget { await _picker.pickImage(source: ImageSource.gallery); if (pickedImage != null) { - Uint8List file = await pickedImage.readAsBytes(); + CroppedFile? croppedFile = await ImageCropper().cropImage( + sourcePath: pickedImage.path, + aspectRatioPresets: [ + CropAspectRatioPreset.square, + CropAspectRatioPreset.ratio3x2, + CropAspectRatioPreset.original, + CropAspectRatioPreset.ratio4x3, + CropAspectRatioPreset.ratio16x9 + ], + uiSettings: [ + AndroidUiSettings( + toolbarTitle: 'Cropper', + toolbarColor: ColorUtils.main, + toolbarWidgetColor: Colors.white, + initAspectRatio: CropAspectRatioPreset.square, + lockAspectRatio: false), + IOSUiSettings( + title: 'Cropper', + ), + ], + ); - callbackFunc(file); + if (croppedFile != null) { + Uint8List file = await croppedFile.readAsBytes(); + callbackFunc(file); + } } }, child: Text(AppLocalizations.of(context)!.profile_picture_select, diff --git a/pubspec.lock b/pubspec.lock index 6452a684..5448f4ac 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -541,6 +541,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.6" + image_cropper: + dependency: "direct main" + description: + name: image_cropper + sha256: f4bad5ed2dfff5a7ce0dfbad545b46a945c702bb6182a921488ef01ba7693111 + url: "https://pub.dev" + source: hosted + version: "5.0.1" + image_cropper_for_web: + dependency: transitive + description: + name: image_cropper_for_web + sha256: "865d798b5c9d826f1185b32e5d0018c4183ddb77b7b82a931e1a06aa3b74974e" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + image_cropper_platform_interface: + dependency: transitive + description: + name: image_cropper_platform_interface + sha256: ee160d686422272aa306125f3b6fb1c1894d9b87a5e20ed33fa008e7285da11e + url: "https://pub.dev" + source: hosted + version: "5.0.0" image_gallery_saver: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 6406b766..dfb42a63 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -69,6 +69,7 @@ dependencies: image_picker: ^1.0.4 share_plus: ^6.3.4 comment_box: ^0.0.18 + image_cropper: ^5.0.1 dev_dependencies: flutter_test: diff --git a/screenshots/community/all_activities.png b/screenshots/community/all_activities.png index a2c9d4a1..90ed7bbf 100644 Binary files a/screenshots/community/all_activities.png and b/screenshots/community/all_activities.png differ