forked from openfoodfacts/smooth-app
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
…#2872) New files: * `crop_grid.dart`: heavily inspired from package `crop_image` - ideally we should put it back there. * `crop_helper.dart`: Crop Helper - which crop tool do we use, and the method to use it. * `new_crop_page.dart`: Page dedicated to image cropping. Pops the resulting file path if relevant. * `rotated_crop_controller.dart`: heavily inspired from package `crop_image` BUT with the rotation feature - ideally we should put it back there. * `rotated_crop_image.dart`: heavily inspired from package `crop_image` BUT with the rotation feature - ideally we should put it back there. * `rotation.dart`: 90 degree rotations - ideally we should put it back in package `crop_image` Impacted files: * `image_crop_page.dart`: now relying on new class `CropHelper` in order to get the appropriate crop tool (e.g. old or new) * `pubspec.lock`: wtf * `pubspec.yaml`: added package `image` for good performances regarding image encoding * `user_preferences_dev_mode.dart`: added a "Use new crop tool" switch (default is `false`)
- Loading branch information
1 parent
b102b42
commit 535cddc
Showing
10 changed files
with
1,135 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import 'dart:io'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||
import 'package:image_cropper/image_cropper.dart'; | ||
import 'package:provider/provider.dart'; | ||
import 'package:smooth_app/data_models/user_preferences.dart'; | ||
import 'package:smooth_app/pages/preferences/user_preferences_dev_mode.dart'; | ||
import 'package:smooth_app/tmp_crop_image/new_crop_page.dart'; | ||
|
||
/// Crop Helper - which crop tool do we use, and the method to use it. | ||
abstract class CropHelper { | ||
/// Returns the crop tool selected in the dev mode preferences. | ||
static CropHelper getCurrent(final BuildContext context) => context | ||
.read<UserPreferences>() | ||
.getFlag(UserPreferencesDevMode.userPreferencesFlagNewCropTool) ?? | ||
false | ||
? _NewCropHelper() | ||
: _OldCropHelper(); | ||
|
||
/// Returns the path of the image file after the crop operation. | ||
Future<String?> getCroppedPath( | ||
final BuildContext context, | ||
final String inputPath, | ||
); | ||
} | ||
|
||
/// New version of the image cropper. | ||
class _NewCropHelper extends CropHelper { | ||
@override | ||
Future<String?> getCroppedPath( | ||
final BuildContext context, | ||
final String inputPath, | ||
) async => | ||
Navigator.push<String>( | ||
context, | ||
MaterialPageRoute<String>( | ||
builder: (BuildContext context) => CropPage(File(inputPath)), | ||
fullscreenDialog: true, | ||
), | ||
); | ||
} | ||
|
||
/// Image cropper based on image_cropper. To be forgotten. | ||
class _OldCropHelper extends CropHelper { | ||
@override | ||
Future<String?> getCroppedPath( | ||
final BuildContext context, | ||
final String inputPath, | ||
) async => | ||
(await ImageCropper().cropImage( | ||
sourcePath: inputPath, | ||
aspectRatioPresets: <CropAspectRatioPreset>[ | ||
CropAspectRatioPreset.square, | ||
CropAspectRatioPreset.ratio3x2, | ||
CropAspectRatioPreset.original, | ||
CropAspectRatioPreset.ratio4x3, | ||
CropAspectRatioPreset.ratio16x9 | ||
], | ||
uiSettings: <PlatformUiSettings>[ | ||
AndroidUiSettings( | ||
initAspectRatio: CropAspectRatioPreset.original, | ||
lockAspectRatio: false, | ||
toolbarTitle: AppLocalizations.of(context).product_edit_photo_title, | ||
// They all need to be the same for dark/light mode as we can't change | ||
// the background color and the action bar color | ||
statusBarColor: Colors.black, | ||
toolbarWidgetColor: Colors.black, | ||
backgroundColor: Colors.black, | ||
activeControlsWidgetColor: const Color(0xFF85746C), | ||
), | ||
], | ||
)) | ||
?.path; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import 'dart:ui'; | ||
|
||
import 'package:flutter/material.dart'; | ||
|
||
class CropGrid extends StatelessWidget { | ||
const CropGrid({ | ||
Key? key, | ||
required this.crop, | ||
required this.gridColor, | ||
required this.cornerSize, | ||
required this.thinWidth, | ||
required this.thickWidth, | ||
required this.scrimColor, | ||
required this.alwaysShowThirdLines, | ||
required this.isMoving, | ||
required this.onSize, | ||
}) : super(key: key); | ||
|
||
final Rect crop; | ||
final Color gridColor; | ||
final double cornerSize; | ||
final double thinWidth; | ||
final double thickWidth; | ||
final Color scrimColor; | ||
final bool alwaysShowThirdLines; | ||
final bool isMoving; | ||
final ValueChanged<Size> onSize; | ||
|
||
@override | ||
Widget build(BuildContext context) => RepaintBoundary( | ||
child: CustomPaint(foregroundPainter: _CropGridPainter(this)), | ||
); | ||
} | ||
|
||
class _CropGridPainter extends CustomPainter { | ||
_CropGridPainter(this.grid); | ||
|
||
final CropGrid grid; | ||
|
||
@override | ||
void paint(Canvas canvas, Size size) { | ||
final Rect full = Offset.zero & size; | ||
final Rect bounds = Rect.fromLTRB( | ||
grid.crop.left * full.width, | ||
grid.crop.top * full.height, | ||
grid.crop.right * full.width, | ||
grid.crop.bottom * full.height, | ||
); | ||
grid.onSize(size); | ||
|
||
canvas.save(); | ||
canvas.clipRect(bounds, clipOp: ClipOp.difference); | ||
canvas.drawRect( | ||
full, | ||
Paint() // | ||
..color = grid.scrimColor | ||
..style = PaintingStyle.fill | ||
..isAntiAlias = true); | ||
canvas.restore(); | ||
|
||
canvas.drawPath( | ||
Path() | ||
..addPolygon(<Offset>[ | ||
bounds.topLeft.translate(0, grid.cornerSize), | ||
bounds.topLeft, | ||
bounds.topLeft.translate(grid.cornerSize, 0) | ||
], false) | ||
..addPolygon(<Offset>[ | ||
bounds.topRight.translate(0, grid.cornerSize), | ||
bounds.topRight, | ||
bounds.topRight.translate(-grid.cornerSize, 0) | ||
], false) | ||
..addPolygon(<Offset>[ | ||
bounds.bottomLeft.translate(0, -grid.cornerSize), | ||
bounds.bottomLeft, | ||
bounds.bottomLeft.translate(grid.cornerSize, 0) | ||
], false) | ||
..addPolygon(<Offset>[ | ||
bounds.bottomRight.translate(0, -grid.cornerSize), | ||
bounds.bottomRight, | ||
bounds.bottomRight.translate(-grid.cornerSize, 0) | ||
], false), | ||
Paint() | ||
..color = grid.gridColor | ||
..style = PaintingStyle.stroke | ||
..strokeWidth = grid.thickWidth | ||
..strokeCap = StrokeCap.round | ||
..strokeJoin = StrokeJoin.miter | ||
..isAntiAlias = true); | ||
|
||
final Path path = Path() | ||
..addPolygon(<Offset>[ | ||
bounds.topLeft.translate(grid.cornerSize, 0), | ||
bounds.topRight.translate(-grid.cornerSize, 0) | ||
], false) | ||
..addPolygon(<Offset>[ | ||
bounds.bottomLeft.translate(grid.cornerSize, 0), | ||
bounds.bottomRight.translate(-grid.cornerSize, 0) | ||
], false) | ||
..addPolygon(<Offset>[ | ||
bounds.topLeft.translate(0, grid.cornerSize), | ||
bounds.bottomLeft.translate(0, -grid.cornerSize) | ||
], false) | ||
..addPolygon(<Offset>[ | ||
bounds.topRight.translate(0, grid.cornerSize), | ||
bounds.bottomRight.translate(0, -grid.cornerSize) | ||
], false); | ||
|
||
if (grid.isMoving || grid.alwaysShowThirdLines) { | ||
final double thirdHeight = bounds.height / 3.0; | ||
path.addPolygon(<Offset>[ | ||
bounds.topLeft.translate(0, thirdHeight), | ||
bounds.topRight.translate(0, thirdHeight) | ||
], false); | ||
path.addPolygon(<Offset>[ | ||
bounds.bottomLeft.translate(0, -thirdHeight), | ||
bounds.bottomRight.translate(0, -thirdHeight) | ||
], false); | ||
|
||
final double thirdWidth = bounds.width / 3.0; | ||
path.addPolygon(<Offset>[ | ||
bounds.topLeft.translate(thirdWidth, 0), | ||
bounds.bottomLeft.translate(thirdWidth, 0) | ||
], false); | ||
path.addPolygon(<Offset>[ | ||
bounds.topRight.translate(-thirdWidth, 0), | ||
bounds.bottomRight.translate(-thirdWidth, 0) | ||
], false); | ||
} | ||
|
||
canvas.drawPath( | ||
path, | ||
Paint() | ||
..color = grid.gridColor | ||
..style = PaintingStyle.stroke | ||
..strokeWidth = grid.thinWidth | ||
..strokeCap = StrokeCap.round | ||
..strokeJoin = StrokeJoin.miter | ||
..isAntiAlias = true); | ||
} | ||
|
||
@override | ||
bool shouldRepaint(_CropGridPainter oldDelegate) => | ||
oldDelegate.grid.crop != grid.crop || // | ||
oldDelegate.grid.isMoving != grid.isMoving; | ||
|
||
@override | ||
bool hitTest(Offset position) => true; | ||
} |
Oops, something went wrong.