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

Feature/add change crop by size #56

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions example/lib/pages/camera/wechat_camera_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class WeChatCameraPicker extends StatelessWidget with InstaPickerInterface {
),
);
},
changeCropBasedOnImageSize: (p0) async {
return InstaAssetCropDelegate(cropRatios: [1, 4 / 5, 16 / 9]);
},
// since the list is revert, use prepend to be at the top
specialItemPosition: SpecialItemPosition.prepend,
),
Expand Down
27 changes: 19 additions & 8 deletions lib/src/assets_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ class InstaAssetCropDelegate {
class InstaAssetPickerConfig {
const InstaAssetPickerConfig({
/// [DefaultAssetPickerBuilderDelegate] config

required this.pickerTheme,
this.gridCount = _kGridCount,
this.pickerTheme,
this.specialItemPosition,
this.specialItemBuilder,
this.loadingIndicatorBuilder,
Expand All @@ -49,6 +48,7 @@ class InstaAssetPickerConfig {
this.gridThumbnailSize = defaultAssetGridPreviewSize,
this.previewThumbnailSize,
this.pathNameBuilder,
this.changeCropBasedOnImageSize,

/// [InstaAssetPickerBuilder] config

Expand Down Expand Up @@ -129,6 +129,14 @@ class InstaAssetPickerConfig {
///
/// Default is unselect all assets button.
final InstaPickerActionsBuilder? actionsBuilder;

/// This [Function] is called when an asset is selected.
///
/// It receives de [AssetEntity] selected and can change the crop based on imageSize.
/// For example, if your first image is vertical, you can set the crop to 4:5.
/// And if it is horizontal, you can set the crop to 16:9.
final Future<InstaAssetCropDelegate> Function(AssetEntity)?
changeCropBasedOnImageSize;
}

class InstaAssetPicker {
Expand Down Expand Up @@ -249,15 +257,16 @@ class InstaAssetPicker {
required DefaultAssetPickerProvider Function() provider,
required Function(Stream<InstaAssetsExportDetails> exportDetails)
onCompleted,
InstaAssetPickerConfig pickerConfig = const InstaAssetPickerConfig(),
InstaAssetPickerConfig? pickerConfig,
}) async {
PermissionState? ps;
try {
ps = await _permissionCheck(null);
} catch (e) {
_openErrorPermission(
context,
pickerConfig.textDelegate,
(pickerConfig?.textDelegate ??
InstaAssetPickerConfig(pickerTheme: ThemeData()).textDelegate),
onPermissionDenied,
);
return [];
Expand All @@ -272,7 +281,7 @@ class InstaAssetPicker {
provider: restoredProvider,
keepScrollOffset: true,
onCompleted: onCompleted,
config: pickerConfig,
config: pickerConfig ?? InstaAssetPickerConfig(pickerTheme: ThemeData()),
locale: Localizations.maybeLocaleOf(context),
);

Expand Down Expand Up @@ -342,7 +351,7 @@ class InstaAssetPicker {
/// InstaAssetPickerBuilder parameters
required Function(Stream<InstaAssetsExportDetails> exportDetails)
onCompleted,
InstaAssetPickerConfig pickerConfig = const InstaAssetPickerConfig(),
InstaAssetPickerConfig? pickerConfig,

/// DefaultAssetPickerProvider parameters
List<AssetEntity>? selectedAssets,
Expand All @@ -365,7 +374,8 @@ class InstaAssetPicker {
} catch (e) {
_openErrorPermission(
context,
pickerConfig.textDelegate,
(pickerConfig?.textDelegate ??
InstaAssetPickerConfig(pickerTheme: ThemeData()).textDelegate),
onPermissionDenied,
);
return [];
Expand All @@ -388,8 +398,9 @@ class InstaAssetPicker {
provider: provider,
keepScrollOffset: false,
onCompleted: onCompleted,
config: pickerConfig,
config: pickerConfig ?? InstaAssetPickerConfig(pickerTheme: ThemeData()),
locale: Localizations.maybeLocaleOf(context),
changeCropBasedOnImageSize: pickerConfig?.changeCropBasedOnImageSize,
);

return AssetPicker.pickAssetsWithDelegate(
Expand Down
10 changes: 5 additions & 5 deletions lib/src/insta_assets_crop_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class InstaAssetsCropController {
ValueNotifier<AssetEntity?>(null);

/// Options related to crop
final InstaAssetCropDelegate cropDelegate;
final ValueNotifier<InstaAssetCropDelegate> cropDelegate;

/// List of all the crop parameters set by the user
List<InstaAssetsCropData> _cropParameters = [];
Expand All @@ -134,9 +134,9 @@ class InstaAssetsCropController {
}

double get aspectRatio {
assert(cropDelegate.cropRatios.isNotEmpty,
assert(cropDelegate.value.cropRatios.isNotEmpty,
'The list of supported crop ratios cannot be empty.');
return cropDelegate.cropRatios[cropRatioIndex.value];
return cropDelegate.value.cropRatios[cropRatioIndex.value];
}

String get aspectRatioString {
Expand All @@ -147,7 +147,7 @@ class InstaAssetsCropController {

/// Set the next available index as the selected crop ratio
void nextCropRatio() {
if (cropRatioIndex.value < cropDelegate.cropRatios.length - 1) {
if (cropRatioIndex.value < cropDelegate.value.cropRatios.length - 1) {
cropRatioIndex.value = cropRatioIndex.value + 1;
} else {
cropRatioIndex.value = 0;
Expand Down Expand Up @@ -257,7 +257,7 @@ class InstaAssetsCropController {
// makes the sample file to not be too small
final sampledFile = await InstaAssetsCrop.sampleImage(
file: file,
preferredSize: (cropDelegate.preferredSize / scale).round(),
preferredSize: (cropDelegate.value.preferredSize / scale).round(),
);

if (area == null) {
Expand Down
26 changes: 13 additions & 13 deletions lib/src/widget/crop_viewer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class CropViewerState extends State<CropViewer> {

// hide crop button if an asset is selected or if there is only one crop
final hideCropButton = selected.length > 1 ||
widget.controller.cropDelegate.cropRatios.length <= 1;
widget.controller.cropDelegate.value.cropRatios.length <= 1;

return ValueListenableBuilder<int>(
valueListenable: widget.controller.cropRatioIndex,
Expand Down Expand Up @@ -305,18 +305,18 @@ class _InnerCropViewState extends State<InnerCropView>
),
size: 32,
// if crop ratios are the default ones, build UI similar to instagram
icon:
widget.controller.cropDelegate.cropRatios == kDefaultInstaCropRatios
? Transform.rotate(
angle: 45 * math.pi / 180,
child: Icon(
widget.controller.aspectRatio == 1
? Icons.unfold_more
: Icons.unfold_less,
),
)
// otherwise simply display the selected aspect ratio
: Text(widget.controller.aspectRatioString),
icon: widget.controller.cropDelegate.value.cropRatios ==
kDefaultInstaCropRatios
? Transform.rotate(
angle: 45 * math.pi / 180,
child: Icon(
widget.controller.aspectRatio == 1
? Icons.unfold_more
: Icons.unfold_less,
),
)
// otherwise simply display the selected aspect ratio
: Text(widget.controller.aspectRatioString),
),
);
}
Expand Down
23 changes: 20 additions & 3 deletions lib/src/widget/insta_asset_picker_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ class InstaAssetPickerBuilder extends DefaultAssetPickerBuilderDelegate {
required super.provider,
required this.onCompleted,
required InstaAssetPickerConfig config,
this.changeCropBasedOnImageSize,
super.keepScrollOffset,
super.locale,
}) : _cropController =
InstaAssetsCropController(keepScrollOffset, config.cropDelegate),
}) : _cropController = InstaAssetsCropController(keepScrollOffset,
ValueNotifier<InstaAssetCropDelegate>(config.cropDelegate)),
title = config.title,
closeOnComplete = config.closeOnComplete,
skipCropOnComplete = config.skipCropOnComplete,
Expand Down Expand Up @@ -79,6 +80,14 @@ class InstaAssetPickerBuilder extends DefaultAssetPickerBuilderDelegate {
/// Defaults to `false`, like instagram
final bool closeOnComplete;

/// This [Function] is called when an asset is selected.
///
/// It receives de [AssetEntity] selected and can change the crop based on imageSize.
/// For example, if your first image is vertical, you can set the crop to 4:5.
/// And if it is horizontal, you can set the crop to 16:9.
final Future<InstaAssetCropDelegate> Function(AssetEntity)?
changeCropBasedOnImageSize;

/// Should the picker automatically crop when the selection is confirmed
///
/// Defaults to `false`.
Expand Down Expand Up @@ -109,6 +118,7 @@ class InstaAssetPickerBuilder extends DefaultAssetPickerBuilderDelegate {
_cropController.dispose();
_cropViewPosition.dispose();
}

super.dispose();
}

Expand Down Expand Up @@ -196,6 +206,7 @@ class InstaAssetPickerBuilder extends DefaultAssetPickerBuilderDelegate {
if (_cropController.isCropViewReady.value != true) {
return;
}

// if is preview asset, unselect it
if (provider.selectedAssets.isNotEmpty &&
_cropController.previewAsset.value == currentAsset) {
Expand All @@ -205,9 +216,15 @@ class InstaAssetPickerBuilder extends DefaultAssetPickerBuilderDelegate {
: provider.selectedAssets.last;
return;
}

_cropController.previewAsset.value = currentAsset;
selectAsset(context, currentAsset, index, false);

InstaAssetCropDelegate? result =
await changeCropBasedOnImageSize?.call(currentAsset);
if (result != null) {
_cropController.cropDelegate.value =
InstaAssetCropDelegate(cropRatios: result.cropRatios);
}
}

/// Called when an asset is selected
Expand Down
5 changes: 3 additions & 2 deletions test/insta_assets_picker_test.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:insta_assets_picker/insta_assets_picker.dart';
import 'package:insta_assets_picker/src/insta_assets_crop_controller.dart';

void main() {
test('Ensure nextCropRatio() loop', () {
final InstaAssetsCropController controller =
InstaAssetsCropController(false, const InstaAssetCropDelegate());
final InstaAssetsCropController controller = InstaAssetsCropController(
false, ValueNotifier(InstaAssetCropDelegate()));

expect(controller.aspectRatio, 1);
expect(controller.aspectRatioString, '1:1');
Expand Down