Skip to content

Commit 8dff471

Browse files
Merge pull request #3 from icapps/feature/nullsafety
nullsafety migration
2 parents 3870e45 + e2490cd commit 8dff471

9 files changed

Lines changed: 73 additions & 72 deletions

File tree

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ You can provide the image using any Imageprovider.
1515

1616
## Parameters
1717

18-
### @required image
18+
### required image
1919
The image that needs to be cropped
2020

2121
### cropController
@@ -69,16 +69,16 @@ class MyHomePage extends StatefulWidget {
6969
final String title;
7070
7171
MyHomePage({
72-
@required this.title,
73-
Key key,
72+
required this.title,
73+
Key? key,
7474
}) : super(key: key);
7575
7676
@override
7777
_MyHomePageState createState() => _MyHomePageState();
7878
}
7979
8080
class _MyHomePageState extends State<MyHomePage> {
81-
CustomImageCropController controller;
81+
late CustomImageCropController controller;
8282
8383
@override
8484
void initState() {
@@ -118,7 +118,9 @@ class _MyHomePageState extends State<MyHomePage> {
118118
icon: const Icon(Icons.crop),
119119
onPressed: () async {
120120
final image = await controller.onCropImage();
121-
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => ResultScreen(image: image)));
121+
if (image != null) {
122+
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => ResultScreen(image: image)));
123+
}
122124
},
123125
),
124126
],

example/lib/main.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ class MyHomePage extends StatefulWidget {
2626
final String title;
2727

2828
MyHomePage({
29-
@required this.title,
30-
Key key,
29+
required this.title,
30+
Key? key,
3131
}) : super(key: key);
3232

3333
@override
3434
_MyHomePageState createState() => _MyHomePageState();
3535
}
3636

3737
class _MyHomePageState extends State<MyHomePage> {
38-
CustomImageCropController controller;
38+
late CustomImageCropController controller;
3939

4040
@override
4141
void initState() {
@@ -75,7 +75,9 @@ class _MyHomePageState extends State<MyHomePage> {
7575
icon: const Icon(Icons.crop),
7676
onPressed: () async {
7777
final image = await controller.onCropImage();
78-
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => ResultScreen(image: image)));
78+
if (image != null) {
79+
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => ResultScreen(image: image)));
80+
}
7981
},
8082
),
8183
],

example/lib/resultScreen.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ class ResultScreen extends StatelessWidget {
44
final MemoryImage image;
55

66
const ResultScreen({
7-
@required this.image,
8-
Key key,
7+
required this.image,
8+
Key? key,
99
}) : super(key: key);
1010

1111
@override

example/pubspec.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ packages:
8080
name: gesture_x_detector
8181
url: "https://pub.dartlang.org"
8282
source: hosted
83-
version: "0.0.5"
83+
version: "1.0.0"
8484
matcher:
8585
dependency: transitive
8686
description:
@@ -164,5 +164,5 @@ packages:
164164
source: hosted
165165
version: "2.1.0"
166166
sdks:
167-
dart: ">=2.12.0-0.0 <3.0.0"
168-
flutter: ">=1.17.0"
167+
dart: ">=2.12.0 <3.0.0"
168+
flutter: ">=2.0.2"

example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ publish_to: 'none'
55
version: 1.0.0+1
66

77
environment:
8-
sdk: ">=2.7.0 <3.0.0"
8+
sdk: '>=2.12.0 <3.0.0'
99

1010
dependencies:
1111
flutter:

lib/src/controllers/controller.dart

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,9 @@ import 'package:flutter/material.dart';
44
class CustomImageCropController {
55
final listeners = <CustomImageCropListener>[];
66

7-
Future<MemoryImage> onCropImage() => listeners.map((e) => e.onCropImage()).firstWhere(
8-
(element) => element != null,
9-
orElse: () => null,
10-
);
7+
Future<MemoryImage?> onCropImage() => listeners.map((e) => e.onCropImage()).first;
118

12-
CropImageData get cropImageData => listeners.map((e) => e.data).firstWhere(
13-
(element) => element != null,
14-
orElse: () => null,
15-
);
9+
CropImageData? get cropImageData => listeners.map((e) => e.data).first;
1610

1711
void addListener(CustomImageCropListener listener) => listeners.add(listener);
1812

@@ -36,5 +30,5 @@ mixin CustomImageCropListener {
3630

3731
void setData(CropImageData transition);
3832

39-
Future<MemoryImage> onCropImage();
33+
Future<MemoryImage?> onCropImage();
4034
}

lib/src/widgets/custom_image_crop_widget.dart

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,27 @@ class CustomImageCrop extends StatefulWidget {
3838
/// `DottedCropPathPainter.drawPath` and
3939
/// `SolidCropPathPainter.drawPath`
4040
const CustomImageCrop({
41-
@required this.image,
42-
@required this.cropController,
43-
Key key,
41+
required this.image,
42+
required this.cropController,
4443
this.overlayColor = const Color.fromRGBO(0, 0, 0, 0.5),
4544
this.backgroundColor = Colors.white,
4645
this.shape = CustomCropShape.Circle,
4746
this.cropPercentage = 0.8,
4847
this.drawPath = DottedCropPathPainter.drawPath,
48+
Key? key,
4949
}) : super(key: key);
5050

5151
@override
5252
_CustomImageCropState createState() => _CustomImageCropState();
5353
}
5454

5555
class _CustomImageCropState extends State<CustomImageCrop> with CustomImageCropListener {
56-
CropImageData dataTransitionStart;
57-
Path path;
58-
double width, height;
59-
ui.Image imageAsUIImage;
60-
ImageStream _imageStream;
61-
ImageStreamListener _imageListener;
56+
CropImageData? dataTransitionStart;
57+
late Path path;
58+
late double width, height;
59+
ui.Image? imageAsUIImage;
60+
ImageStream? _imageStream;
61+
ImageStreamListener? _imageListener;
6262

6363
@override
6464
void initState() {
@@ -75,10 +75,12 @@ class _CustomImageCropState extends State<CustomImageCrop> with CustomImageCropL
7575
void _getImage() {
7676
final oldImageStream = _imageStream;
7777
_imageStream = widget.image.resolve(createLocalImageConfiguration(context));
78-
if (_imageStream.key != oldImageStream?.key) {
79-
oldImageStream?.removeListener(_imageListener);
78+
if (_imageStream?.key != oldImageStream?.key) {
79+
if (_imageListener != null) {
80+
oldImageStream?.removeListener(_imageListener!);
81+
}
8082
_imageListener = ImageStreamListener(_updateImage);
81-
_imageStream.addListener(_imageListener);
83+
_imageStream?.addListener(_imageListener!);
8284
}
8385
}
8486

@@ -90,22 +92,25 @@ class _CustomImageCropState extends State<CustomImageCrop> with CustomImageCropL
9092

9193
@override
9294
void dispose() {
93-
_imageStream?.removeListener(_imageListener);
95+
if (_imageListener != null) {
96+
_imageStream?.removeListener(_imageListener!);
97+
}
9498
widget.cropController.removeListener(this);
9599
super.dispose();
96100
}
97101

98102
@override
99103
Widget build(BuildContext context) {
100-
if (imageAsUIImage == null) {
104+
final image = imageAsUIImage;
105+
if (image == null) {
101106
return const Center(child: CircularProgressIndicator());
102107
}
103108
return LayoutBuilder(
104109
builder: (context, constraints) {
105110
width = constraints.maxWidth;
106111
height = constraints.maxHeight;
107112
final cropWidth = min(width, height) * widget.cropPercentage;
108-
final defaultScale = min(imageAsUIImage.width, imageAsUIImage.height) / cropWidth;
113+
final defaultScale = min(image.width, image.height) / cropWidth;
109114
final scale = data.scale * defaultScale;
110115
path = _getPath(cropWidth, width, height);
111116
return XGestureDetector(
@@ -125,7 +130,7 @@ class _CustomImageCropState extends State<CustomImageCrop> with CustomImageCropL
125130
child: Transform(
126131
transform: Matrix4.diagonal3(vector_math.Vector3(scale, scale, 0))
127132
..rotateZ(data.angle)
128-
..translate(-imageAsUIImage.width / 2, -imageAsUIImage.height / 2),
133+
..translate(-image.width / 2, -image.height / 2),
129134
child: Image(
130135
image: widget.image,
131136
),
@@ -139,9 +144,7 @@ class _CustomImageCropState extends State<CustomImageCrop> with CustomImageCropL
139144
),
140145
),
141146
),
142-
if (widget.drawPath != null) ...{
143-
widget.drawPath(path),
144-
},
147+
widget.drawPath(path),
145148
],
146149
),
147150
),
@@ -156,7 +159,7 @@ class _CustomImageCropState extends State<CustomImageCrop> with CustomImageCropL
156159

157160
void onScaleUpdate(ScaleEvent event) {
158161
if (dataTransitionStart != null) {
159-
addTransition(dataTransitionStart - CropImageData(scale: event.scale, angle: event.rotationAngle));
162+
addTransition(dataTransitionStart! - CropImageData(scale: event.scale, angle: event.rotationAngle));
160163
}
161164
dataTransitionStart = CropImageData(scale: event.scale, angle: event.rotationAngle);
162165
}
@@ -192,14 +195,14 @@ class _CustomImageCropState extends State<CustomImageCrop> with CustomImageCropL
192195
}
193196

194197
@override
195-
Future<MemoryImage> onCropImage() async {
198+
Future<MemoryImage?> onCropImage() async {
196199
if (imageAsUIImage == null) {
197200
return null;
198201
}
199202
final cropWidth = min(width, height) * widget.cropPercentage;
200203
final pictureRecorder = ui.PictureRecorder();
201204
final canvas = Canvas(pictureRecorder);
202-
final defaultScale = min(imageAsUIImage.width, imageAsUIImage.height) / cropWidth;
205+
final defaultScale = min(imageAsUIImage!.width, imageAsUIImage!.height) / cropWidth;
203206
final scale = data.scale * defaultScale;
204207
final clipPath = Path.from(_getPath(cropWidth, cropWidth, cropWidth));
205208
final matrix4Image = Matrix4.diagonal3(vector_math.Vector3(1, 1, 0))
@@ -214,7 +217,7 @@ class _CustomImageCropState extends State<CustomImageCrop> with CustomImageCropL
214217
canvas.save();
215218
canvas.clipPath(clipPath);
216219
canvas.transform(matrix4Image.storage);
217-
canvas.drawImage(imageAsUIImage, Offset(-imageAsUIImage.width / 2, -imageAsUIImage.height / 2), imagePaint);
220+
canvas.drawImage(imageAsUIImage!, Offset(-imageAsUIImage!.width / 2, -imageAsUIImage!.height / 2), imagePaint);
218221
canvas.restore();
219222

220223
// Optionally remove magenta from image by evaluating every pixel
@@ -228,7 +231,7 @@ class _CustomImageCropState extends State<CustomImageCrop> with CustomImageCropL
228231
// A workaround would be to save the image and load it inside of the isolate
229232
final bytes = await image.toByteData(format: ui.ImageByteFormat.png);
230233

231-
return MemoryImage(bytes.buffer.asUint8List());
234+
return bytes == null ? null : MemoryImage(bytes.buffer.asUint8List());
232235
}
233236

234237
@override

0 commit comments

Comments
 (0)