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

refactor: Update TaroResizeOption to use sealed classes #48

Merged
merged 1 commit into from
Aug 1, 2024
Merged
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
12 changes: 4 additions & 8 deletions lib/src/taro.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,7 @@ class Taro {
final _loader = TaroLoader();

/// The [TaroResizeOption] used to resize images.
TaroResizeOption _resizeOption = const (
mode: TaroResizeMode.skip,
maxWidth: null,
maxHeight: null,
);
TaroResizeOption _resizeOption = const TaroResizeOptionSkip();

/// The [TaroResizeOption] used to resize images.
/// Changing this option will affect all image loading.
Expand Down Expand Up @@ -94,10 +90,10 @@ class Taro {
headerOption: headerOption ?? _headerOption,
);

if (resizeOption?.mode == TaroResizeMode.memory) {
if (resizeOption is TaroResizeOptionMemory) {
return ResizeImage.resizeIfNeeded(
resizeOption?.maxWidth,
resizeOption?.maxHeight,
resizeOption.maxWidth,
resizeOption.maxHeight,
image,
);
}
Expand Down
187 changes: 94 additions & 93 deletions lib/src/taro_resizer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,116 +16,117 @@ class TaroResizer {
required String contentType,
required TaroResizeOption resizeOption,
}) async {
if (resizeOption.mode case TaroResizeMode.skip || TaroResizeMode.memory) {
// do nothing
return (
bytes: bytes,
contentType: contentType,
);
}
switch (resizeOption) {
case TaroResizeOptionSkip() || TaroResizeOptionMemory():
// do nothing
return (
bytes: bytes,
contentType: contentType,
);
case TaroResizeOptionDisk(
format: final optionFormat,
maxWidth: final optionMaxWidth,
maxHeight: final optionMaxHeight,
):
final originalImage = img.decodeImage(bytes);
if (originalImage == null) {
return throw TaroResizeException(
exception: Exception('Failed to decode image.'),
);
}

final originalImage = img.decodeImage(bytes);
if (originalImage == null) {
return throw TaroResizeException(
exception: Exception('Failed to decode image.'),
);
}
final int maxWidth;
if (optionMaxWidth != null) {
maxWidth = min(optionMaxWidth, originalImage.width);
} else {
maxWidth = originalImage.width;
}

final int maxWidth;
if (resizeOption.maxWidth != null) {
maxWidth = min(resizeOption.maxWidth!, originalImage.width);
} else {
maxWidth = originalImage.width;
}
final int maxHeight;
if (optionMaxHeight != null) {
maxHeight = min(optionMaxHeight, originalImage.height);
} else {
maxHeight = originalImage.height;
}

final int maxHeight;
if (resizeOption.maxHeight != null) {
maxHeight = min(resizeOption.maxHeight!, originalImage.height);
} else {
maxHeight = originalImage.height;
}
if (maxWidth == originalImage.width &&
maxHeight == originalImage.height) {
return (
bytes: bytes,
contentType: contentType,
);
}

if (maxWidth == originalImage.width && maxHeight == originalImage.height) {
return (
bytes: bytes,
contentType: contentType,
);
}
final cmd = img.Command()
..image(originalImage)
..copyResize(
width: maxWidth,
height: maxHeight,
);

final cmd = img.Command()
..image(originalImage)
..copyResize(
width: maxWidth,
height: maxHeight,
);
final String encodeImageType;
switch (optionFormat) {
case TaroResizeFormat.original:
switch (contentType) {
case 'image/gif':
case 'image/jpeg':
case 'image/png':
case 'image/bmp':
case 'image/x-icon':
case 'image/tiff':
encodeImageType = contentType;
default:
encodeImageType = 'image/png';
}
case TaroResizeFormat.gif:
encodeImageType = 'image/gif';
case TaroResizeFormat.jpeg:
encodeImageType = 'image/jpeg';
case TaroResizeFormat.png:
encodeImageType = 'image/png';
case TaroResizeFormat.bmp:
encodeImageType = 'image/bmp';
case TaroResizeFormat.ico:
encodeImageType = 'image/x-icon';
case TaroResizeFormat.tiff:
encodeImageType = 'image/tiff';
}

final String encodeImageType;
switch (resizeOption.mode) {
case TaroResizeMode.skip:
// this case is not possible
throw Exception('This case is not possible.');
case TaroResizeMode.original:
switch (contentType) {
switch (encodeImageType) {
case 'image/gif':
cmd.encodeGif();
case 'image/jpeg':
cmd.encodeJpg();
case 'image/png':
cmd.encodePng();
case 'image/bmp':
cmd.encodeBmp();
case 'image/x-icon':
cmd.encodeIco();
case 'image/tiff':
encodeImageType = contentType;
cmd.encodeTiff();
default:
encodeImageType = 'image/png';
// if the contentType is not supported, encode the image to png
cmd.encodePng();
}
case TaroResizeMode.gif:
encodeImageType = 'image/gif';
case TaroResizeMode.jpeg:
encodeImageType = 'image/jpeg';
case TaroResizeMode.png:
encodeImageType = 'image/png';
case TaroResizeMode.bmp:
encodeImageType = 'image/bmp';
case TaroResizeMode.ico:
encodeImageType = 'image/x-icon';
case TaroResizeMode.tiff:
encodeImageType = 'image/tiff';
default:
encodeImageType = 'image/png';
}

switch (encodeImageType) {
case 'image/gif':
cmd.encodeGif();
case 'image/jpeg':
cmd.encodeJpg();
case 'image/png':
cmd.encodePng();
case 'image/bmp':
cmd.encodeBmp();
case 'image/x-icon':
cmd.encodeIco();
case 'image/tiff':
cmd.encodeTiff();
default:
// if the contentType is not supported, encode the image to png
cmd.encodePng();
}
final Uint8List? result;
try {
result = await cmd.getBytesThread();
} on Exception catch (exception) {
throw TaroResizeException(
exception: exception,
);
}

final Uint8List? result;
try {
result = await cmd.getBytesThread();
} on Exception catch (exception) {
throw TaroResizeException(
exception: exception,
);
}
if (result == null) {
throw const TaroResizeFailedException();
}

if (result == null) {
throw const TaroResizeFailedException();
return (
bytes: result,
contentType: encodeImageType,
);
}

return (
bytes: result,
contentType: encodeImageType,
);
}
}
68 changes: 45 additions & 23 deletions lib/src/taro_type.dart
Original file line number Diff line number Diff line change
@@ -1,43 +1,65 @@
/// [TaroRequestOption] is used to configure the options for a resizing request.
typedef TaroResizeOption = ({
/// The resize mode of the image.
TaroResizeMode mode,
/// The [TaroResizeOption] is used to determine how images are resized and saved.
/// Please refer to [https://pub.dev/packages/image] for supported formats.
sealed class TaroResizeOption {
const TaroResizeOption();
}

/// The maximum width of the image. If null, the width is not limited.
int? maxWidth,
/// The image is not resized, saved original size and format.
class TaroResizeOptionSkip extends TaroResizeOption {
const TaroResizeOptionSkip();
}

/// The maximum height of the image. If null, the height is not limited.
int? maxHeight,
});
/// The image is resized in memory, saved original size and format.
class TaroResizeOptionMemory extends TaroResizeOption {
const TaroResizeOptionMemory({
required this.maxWidth,
required this.maxHeight,
});

/// The [TaroResizeMode] enum is used to determine how images are resized.
/// Please refer to [https://pub.dev/packages/image] for supported formats.
enum TaroResizeMode {
/// The image is not resized.
skip,
/// The maximum width of the image.
final int maxWidth;

/// The image is resized and saved original image.
memory,
/// The maximum height of the image.
final int maxHeight;
}

class TaroResizeOptionDisk extends TaroResizeOption {
const TaroResizeOptionDisk({
required this.format,
this.maxWidth,
this.maxHeight,
});

/// The format of the image.
final TaroResizeFormat format;

/// The maximum width of the image. If null, the width is not limited.
final int? maxWidth;

/// The maximum height of the image. If null, the height is not limited.
final int? maxHeight;
}

/// The image is resized to the original contentType and saved cache.
enum TaroResizeFormat {
/// The original format of the image.
original,

/// The image is resized to a gif and saved cache.
/// The image is saved as a gif.
gif,

/// The image is resized to a jpg and saved cache.
/// The image is saved as a jpeg.
jpeg,

/// The image is resized to a png and saved cache.
/// The image is saved as a png.
png,

/// The image is resized to a bmp and saved cache.
/// The image is saved as a bmp.
bmp,

/// The image is resized to a ico and saved cache.
/// The image is saved as an icon.
ico,

/// The image is resized to a tiff and saved cache.
/// The image is saved as a tiff.
tiff,
}

Expand Down
6 changes: 1 addition & 5 deletions test/taro_loader_network_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@ void main() {
);

final bodyBytes = Uint8List(100);
const resizeOption = (
mode: TaroResizeMode.skip,
maxWidth: null,
maxHeight: null,
);
const resizeOption = TaroResizeOptionSkip();
const headerOption = (
checkMaxAgeIfExist: false,
ifThrowMaxAgeHeaderError: false,
Expand Down
6 changes: 1 addition & 5 deletions test/taro_loader_network_test.mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,7 @@ class MockTaroResizer extends _i1.Mock implements _i5.TaroResizer {
_i3.Future<({_i4.Uint8List bytes, String contentType})> resizeIfNeeded({
required _i4.Uint8List? bytes,
required String? contentType,
required ({
int? maxHeight,
int? maxWidth,
_i6.TaroResizeMode mode
})? resizeOption,
required _i6.TaroResizeOption? resizeOption,
}) =>
(super.noSuchMethod(
Invocation.method(
Expand Down