diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 9adb1728..feaf5061 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -135,4 +135,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 303789365c3a8d7bc562e5e65d7e8e15218ec5c6 -COCOAPODS: 1.15.0 +COCOAPODS: 1.14.3 diff --git a/lib/core/commands/command_implementation/graphic/draw_path_command.g.dart b/lib/core/commands/command_implementation/graphic/draw_path_command.g.dart deleted file mode 100644 index 5711dc2f..00000000 --- a/lib/core/commands/command_implementation/graphic/draw_path_command.g.dart +++ /dev/null @@ -1,23 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'path_command.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -PathCommand _$PathCommandFromJson(Map json) => PathCommand( - const PathWithActionHistoryConverter() - .fromJson(json['path'] as Map), - const PaintConverter().fromJson(json['paint'] as Map), - type: json['type'] as String? ?? SerializerType.PATH_COMMAND, - version: (json['version'] as num?)?.toInt(), - ); - -Map _$PathCommandToJson(PathCommand instance) => - { - 'paint': const PaintConverter().toJson(instance.paint), - 'type': instance.type, - 'version': instance.version, - 'path': const PathWithActionHistoryConverter().toJson(instance.path), - }; diff --git a/lib/core/commands/command_painter.dart b/lib/core/commands/command_painter.dart index 59c3195d..0b33883c 100644 --- a/lib/core/commands/command_painter.dart +++ b/lib/core/commands/command_painter.dart @@ -1,5 +1,6 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Project imports: import 'package:paintroid/core/commands/command_manager/command_manager.dart'; import 'package:paintroid/core/enums/tool_types.dart'; diff --git a/lib/core/enums/image_format.dart b/lib/core/enums/image_format.dart index b0f81771..4ae018e8 100644 --- a/lib/core/enums/image_format.dart +++ b/lib/core/enums/image_format.dart @@ -1,7 +1,8 @@ enum ImageFormat { png('png'), jpg('jpg'), - catrobatImage('catrobat-image'); + catrobatImage('catrobat-image'), + ora('ora'); const ImageFormat(this.extension); diff --git a/lib/core/models/image_from_file.dart b/lib/core/models/image_from_file.dart index 93c5f1e3..2e6089bf 100644 --- a/lib/core/models/image_from_file.dart +++ b/lib/core/models/image_from_file.dart @@ -7,14 +7,22 @@ import 'package:paintroid/core/models/catrobat_image.dart'; class ImageFromFile { final Image? rasterImage; final CatrobatImage? catrobatImage; + final List? oraImageLayers; const ImageFromFile.catrobatImage( CatrobatImage image, { Image? backgroundImage, }) : catrobatImage = image, - rasterImage = backgroundImage; + rasterImage = backgroundImage, + oraImageLayers = null; const ImageFromFile.rasterImage(Image image) : rasterImage = image, + catrobatImage = null, + oraImageLayers = null; + + const ImageFromFile.oraImage(List layers) + : oraImageLayers = layers, + rasterImage = null, catrobatImage = null; } diff --git a/lib/core/models/image_meta_data.dart b/lib/core/models/image_meta_data.dart index 7045acca..111e08a6 100644 --- a/lib/core/models/image_meta_data.dart +++ b/lib/core/models/image_meta_data.dart @@ -29,3 +29,8 @@ class CatrobatImageMetaData extends ImageMetaData { const CatrobatImageMetaData(String name) : super(name, ImageFormat.catrobatImage); } + + +class OraMetaData extends ImageMetaData { + const OraMetaData(String name) : super(name, ImageFormat.ora); +} \ No newline at end of file diff --git a/lib/core/models/ora_image.dart b/lib/core/models/ora_image.dart new file mode 100644 index 00000000..5c995da6 --- /dev/null +++ b/lib/core/models/ora_image.dart @@ -0,0 +1,38 @@ +// Dart imports: +import 'dart:convert'; +import 'dart:typed_data'; + +// Package imports: +import 'package:archive/archive.dart'; +import 'package:image/image.dart' as img; + +class OraImage { + final int width; + final int height; + final List layers; + final String xmlMetadata; + + OraImage({ + required this.width, + required this.height, + required this.layers, + required this.xmlMetadata, + }); + + Uint8List toBytes() { + final archive = Archive(); + + for (int i = 0; i < layers.length; i++) { + final layer = layers[i]; + final encoder = img.PngEncoder(); + final layerData = encoder.encodeImage(layer); + archive.addFile(ArchiveFile('layer_$i.png', layerData.length, layerData)); + } + + final encodedXml = utf8.encode(xmlMetadata); + archive.addFile(ArchiveFile('stack.xml', encodedXml.length, encodedXml)); + + final zipEncoder = ZipEncoder(); + return Uint8List.fromList(zipEncoder.encode(archive)!); + } +} diff --git a/lib/core/models/process_ora.dart b/lib/core/models/process_ora.dart new file mode 100644 index 00000000..b7aacb3c --- /dev/null +++ b/lib/core/models/process_ora.dart @@ -0,0 +1,36 @@ +// Dart imports: +import 'dart:typed_data'; +import 'dart:ui' as ui; + +// Package imports: +import 'package:archive/archive.dart'; +import 'package:image/image.dart' as img; + +class ProcessOra { + Future> processOraFile(Archive archive) async { + List layers = []; + + for (var file in archive) { + if (file.isFile && + (file.name.endsWith('.png') || file.name.endsWith('.jpg')) || + file.name.endsWith('.ora')) { + img.Image? decodedImage = img.decodeImage(file.content as List); + + if (decodedImage != null) { + ui.Image layer = await convertImgImageToUiImage(decodedImage); + layers.add(layer); + } + } + } + + return layers; + } + + Future convertImgImageToUiImage(img.Image image) async { + List pngBytes = img.encodePng(image); + + final codec = await ui.instantiateImageCodec(Uint8List.fromList(pngBytes)); + final frame = await codec.getNextFrame(); + return frame.image; + } +} diff --git a/lib/core/providers/object/image_service.dart b/lib/core/providers/object/image_service.dart index a49a2bdb..b97487f9 100644 --- a/lib/core/providers/object/image_service.dart +++ b/lib/core/providers/object/image_service.dart @@ -8,11 +8,13 @@ import 'package:flutter/painting.dart'; // Package imports: import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:image/image.dart' as img; import 'package:image/image.dart'; import 'package:oxidized/oxidized.dart'; // Project imports: import 'package:paintroid/core/models/loggable_mixin.dart'; +import 'package:paintroid/core/models/ora_image.dart'; import 'package:paintroid/core/utils/failure.dart'; import 'package:paintroid/core/utils/load_image_failure.dart'; import 'package:paintroid/core/utils/save_image_failure.dart'; @@ -25,6 +27,8 @@ abstract class IImageService { Future> exportAsPng(ui.Image image); + Future> exportAsOra(ui.Image image); + Result getProjectPreview(String? path); static final provider = Provider((ref) => ImageService()); @@ -70,6 +74,50 @@ class ImageService with LoggableMixin implements IImageService { } } + @override + Future> exportAsOra(ui.Image image) async { + try { + final img.Image layer = await convertUiImageToImgImage(image); + final oraImage = OraImage( + width: image.width, + height: image.height, + layers: [layer], + xmlMetadata: generateXmlMetadataForOra([layer]), + ); + final bytes = oraImage.toBytes(); + return Result.ok(bytes); + } catch (err, stacktrace) { + logger.severe('Could not export to Ora', err, stacktrace); + return const Result.err(SaveImageFailure.unidentified); + } + } + + Future convertUiImageToImgImage(ui.Image uiImage) async { + final byteData = + await uiImage.toByteData(format: ui.ImageByteFormat.rawRgba); + final buffer = byteData!.buffer.asUint8List(); + + return img.Image.fromBytes( + uiImage.width, + uiImage.height, + buffer, + format: img.Format.rgba, + ); + } + + String generateXmlMetadataForOra(List layers) { + var buffer = StringBuffer(); + buffer.writeln(''); + + for (int i = 0; i < layers.length; i++) { + buffer.writeln( + ''); + } + + buffer.writeln(''); + return buffer.toString(); + } + @override Result getProjectPreview(String? path) { try { diff --git a/lib/core/providers/object/io_handler.dart b/lib/core/providers/object/io_handler.dart index b5e01218..0734bc8e 100644 --- a/lib/core/providers/object/io_handler.dart +++ b/lib/core/providers/object/io_handler.dart @@ -2,12 +2,14 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; +import 'dart:ui' as ui; // Flutter imports: import 'package:flutter/material.dart'; // Package imports: import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:image/image.dart' as img; import 'package:oxidized/oxidized.dart'; // Project imports: @@ -16,12 +18,14 @@ import 'package:paintroid/core/enums/image_format.dart'; import 'package:paintroid/core/enums/image_location.dart'; import 'package:paintroid/core/models/catrobat_image.dart'; import 'package:paintroid/core/models/image_meta_data.dart'; +import 'package:paintroid/core/models/ora_image.dart'; import 'package:paintroid/core/providers/object/file_service.dart'; import 'package:paintroid/core/providers/object/image_service.dart'; import 'package:paintroid/core/providers/object/load_image_from_file_manager.dart'; import 'package:paintroid/core/providers/object/load_image_from_photo_library.dart'; import 'package:paintroid/core/providers/object/render_image_for_export.dart'; import 'package:paintroid/core/providers/object/save_as_catrobat_image.dart'; +import 'package:paintroid/core/providers/object/save_as_ora_image.dart'; import 'package:paintroid/core/providers/object/save_as_raster_image.dart'; import 'package:paintroid/core/providers/state/canvas_state_provider.dart'; import 'package:paintroid/core/providers/state/workspace_state_notifier.dart'; @@ -182,10 +186,67 @@ class IOHandler { } else if (imageData is CatrobatImageMetaData) { final savedFile = await _saveAsCatrobatImage(imageData, false); isImageSaved = (savedFile != null); + } else if (imageData is OraMetaData) { + isImageSaved = await _saveAsOraImage(imageData); } return isImageSaved; } + Future convertUiImageToImgImage(ui.Image uiImage) async { + final byteData = + await uiImage.toByteData(format: ui.ImageByteFormat.rawRgba); + final buffer = byteData!.buffer.asUint8List(); + + return img.Image.fromBytes( + uiImage.width, + uiImage.height, + buffer, + format: img.Format.rgba, + ); + } + + String generateXmlMetadataForOra(List layers) { + var buffer = StringBuffer(); + buffer.writeln(''); + + for (int i = 0; i < layers.length; i++) { + buffer.writeln( + ''); + } + + buffer.writeln(''); + return buffer.toString(); + } + + Future _saveAsOraImage(OraMetaData imageData) async { + final canvasState = ref.read(canvasStateProvider); + final oraImageService = ref.read(SaveAsOraImage.provider); + + if (canvasState.cachedImage == null) { + return false; + } + + final imgWidth = canvasState.size.width.toInt(); + final imgHeight = canvasState.size.height.toInt(); + + img.Image layer = await convertUiImageToImgImage(canvasState.cachedImage!); + + final oraImage = OraImage( + width: imgWidth, + height: imgHeight, + layers: [layer], + xmlMetadata: generateXmlMetadataForOra([layer]), + ); + + final fileName = '${imageData.name}.ora'; + final result = await oraImageService.call(oraImage, fileName); + + return result.match( + (file) => true, + (error) => false, + ); + } + Future _saveAsRasterImage(ImageMetaData imageData) async { final image = await ref .read(RenderImageForExport.provider) diff --git a/lib/core/providers/object/save_as_ora_image.dart b/lib/core/providers/object/save_as_ora_image.dart new file mode 100644 index 00000000..c6384c9e --- /dev/null +++ b/lib/core/providers/object/save_as_ora_image.dart @@ -0,0 +1,35 @@ +// Dart imports: +import 'dart:io'; + +// Package imports: +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:oxidized/oxidized.dart'; + +// Project imports: +import 'package:paintroid/core/models/ora_image.dart'; +import 'package:paintroid/core/providers/object/file_service.dart'; +import 'package:paintroid/core/providers/object/permission_service.dart'; +import 'package:paintroid/core/utils/failure.dart'; +import 'package:paintroid/core/utils/save_image_failure.dart'; + +class SaveAsOraImage { + final IFileService _fileService; + final IPermissionService _permissionService; + + SaveAsOraImage(this._fileService, this._permissionService); + + static final provider = Provider((ref) { + final fileService = ref.watch(IFileService.provider); + final permissionService = ref.watch(IPermissionService.provider); + return SaveAsOraImage(fileService, permissionService); + }); + + Future> call(OraImage image, String fileName) async { + if (!(await _permissionService.requestAccessToSharedFileStorage())) { + return const Result.err(SaveImageFailure.permissionDenied); + } + + final bytes = image.toBytes(); + return _fileService.save(fileName, bytes); + } +} diff --git a/lib/core/tools/line_tool/line_tool.dart b/lib/core/tools/line_tool/line_tool.dart index 51eadd58..3422b213 100644 --- a/lib/core/tools/line_tool/line_tool.dart +++ b/lib/core/tools/line_tool/line_tool.dart @@ -1,10 +1,12 @@ // Dart imports: import 'dart:ui'; -// Package imports: -import 'package:equatable/equatable.dart'; // Flutter imports: import 'package:flutter/material.dart'; + +// Package imports: +import 'package:equatable/equatable.dart'; + // Project imports: import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart'; import 'package:paintroid/core/commands/graphic_factory/graphic_factory.dart'; diff --git a/lib/core/tools/line_tool/vertex.dart b/lib/core/tools/line_tool/vertex.dart index 933a8b77..bfda7ed9 100644 --- a/lib/core/tools/line_tool/vertex.dart +++ b/lib/core/tools/line_tool/vertex.dart @@ -1,6 +1,8 @@ // Dart imports: + // Flutter imports: import 'package:flutter/material.dart'; + // Project imports: import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart'; import 'package:paintroid/core/utils/distance_calculator.dart'; diff --git a/lib/core/utils/distance_calculator.dart b/lib/core/utils/distance_calculator.dart index cf8dfcda..34f71bae 100644 --- a/lib/core/utils/distance_calculator.dart +++ b/lib/core/utils/distance_calculator.dart @@ -1,3 +1,4 @@ +// Dart imports: import 'dart:math'; class DistanceCalculator { diff --git a/lib/ui/pages/landing_page/landing_page.dart b/lib/ui/pages/landing_page/landing_page.dart index aa184cbc..d0816827 100644 --- a/lib/ui/pages/landing_page/landing_page.dart +++ b/lib/ui/pages/landing_page/landing_page.dart @@ -1,8 +1,11 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Package imports: import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:oxidized/oxidized.dart'; +import 'package:toast/toast.dart'; + // Project imports: import 'package:paintroid/core/database/project_database.dart'; import 'package:paintroid/core/models/database/project.dart'; @@ -22,7 +25,6 @@ import 'package:paintroid/ui/pages/landing_page/components/project_overflow_menu import 'package:paintroid/ui/shared/icon_svg.dart'; import 'package:paintroid/ui/theme/theme.dart'; import 'package:paintroid/ui/utils/toast_utils.dart'; -import 'package:toast/toast.dart'; class LandingPage extends ConsumerStatefulWidget { final String title; diff --git a/lib/ui/pages/workspace_page/components/drawing_surface/canvas_painter.dart b/lib/ui/pages/workspace_page/components/drawing_surface/canvas_painter.dart index af697446..4faa2e41 100644 --- a/lib/ui/pages/workspace_page/components/drawing_surface/canvas_painter.dart +++ b/lib/ui/pages/workspace_page/components/drawing_surface/canvas_painter.dart @@ -1,7 +1,9 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Package imports: import 'package:flutter_riverpod/flutter_riverpod.dart'; + // Project imports: import 'package:paintroid/core/commands/command_manager/command_manager_provider.dart'; import 'package:paintroid/core/commands/command_painter.dart'; diff --git a/lib/ui/pages/workspace_page/components/top_bar/top_app_bar.dart b/lib/ui/pages/workspace_page/components/top_bar/top_app_bar.dart index c1cd3e21..f4a9a2c6 100644 --- a/lib/ui/pages/workspace_page/components/top_bar/top_app_bar.dart +++ b/lib/ui/pages/workspace_page/components/top_bar/top_app_bar.dart @@ -1,7 +1,9 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Package imports: import 'package:flutter_riverpod/flutter_riverpod.dart'; + // Project imports: import 'package:paintroid/core/enums/tool_types.dart'; import 'package:paintroid/core/providers/state/checkmark_clicked_state.dart'; diff --git a/lib/ui/shared/dialogs/save_image_dialog.dart b/lib/ui/shared/dialogs/save_image_dialog.dart index 40996834..3ed26d10 100644 --- a/lib/ui/shared/dialogs/save_image_dialog.dart +++ b/lib/ui/shared/dialogs/save_image_dialog.dart @@ -52,6 +52,9 @@ class _SaveImageDialogState extends State { case ImageFormat.catrobatImage: data = CatrobatImageMetaData(nameFieldController.text); break; + case ImageFormat.ora: + data = OraMetaData(nameFieldController.text); + break; } Navigator.of(context).pop(data); } diff --git a/lib/ui/shared/image_format_info.dart b/lib/ui/shared/image_format_info.dart index 98f42574..bdd99afb 100644 --- a/lib/ui/shared/image_format_info.dart +++ b/lib/ui/shared/image_format_info.dart @@ -26,6 +26,11 @@ extension on ImageFormat { return const TextSpan( text: 'Pocket Paint\'s native image format. ' 'This format remembers commands and layers.'); + + case ImageFormat.ora: + return const TextSpan( + text: + 'OpenRaster format. Supports layers and various attributes like opacity and visibility for each layer.'); } } } diff --git a/lib/ui/utils/top_bar_action_data.dart b/lib/ui/utils/top_bar_action_data.dart index 05360676..62b23d87 100644 --- a/lib/ui/utils/top_bar_action_data.dart +++ b/lib/ui/utils/top_bar_action_data.dart @@ -1,4 +1,4 @@ -// Project imports: +// Flutter imports: import 'package:flutter/material.dart'; class TopBarActionData { diff --git a/pubspec.lock b/pubspec.lock index 39fe986c..8ed4f499 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -26,13 +26,13 @@ packages: source: hosted version: "0.11.3" archive: - dependency: transitive + dependency: "direct main" description: name: archive - sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d url: "https://pub.dev" source: hosted - version: "3.5.1" + version: "3.6.1" args: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cc0a8055..f5cfba61 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: file_picker: ^5.3.1 floor: ^1.2.0 sqflite: ^2.3.0 + archive: ^3.6.1 dev_dependencies: flutter_test: @@ -59,7 +60,6 @@ dev_dependencies: import_sorter: ^4.6.0 json_serializable: ^6.7.1 - flutter: uses-material-design: true diff --git a/test/unit/provider/load_image_from_photo_library_test.mocks.dart b/test/unit/provider/load_image_from_photo_library_test.mocks.dart index 11ab4975..3307a2a5 100644 --- a/test/unit/provider/load_image_from_photo_library_test.mocks.dart +++ b/test/unit/provider/load_image_from_photo_library_test.mocks.dart @@ -115,6 +115,24 @@ class MockIImageService extends _i1.Mock implements _i3.IImageService { )), ) as _i4.Future<_i2.Result<_i7.Uint8List, _i6.Failure>>); + @override + _i4.Future<_i2.Result<_i7.Uint8List, _i6.Failure>> exportAsOra( + _i5.Image? image) => + (super.noSuchMethod( + Invocation.method( + #exportAsOra, + [image], + ), + returnValue: _i4.Future<_i2.Result<_i7.Uint8List, _i6.Failure>>.value( + _FakeResult_0<_i7.Uint8List, _i6.Failure>( + this, + Invocation.method( + #exportAsOra, + [image], + ), + )), + ) as _i4.Future<_i2.Result<_i7.Uint8List, _i6.Failure>>); + @override _i2.Result<_i7.Uint8List, _i6.Failure> getProjectPreview(String? path) => (super.noSuchMethod( diff --git a/test/unit/provider/save_as_raster_image_test.dart b/test/unit/provider/save_as_raster_image_test.dart index cb7dffac..02ed13b4 100644 --- a/test/unit/provider/save_as_raster_image_test.dart +++ b/test/unit/provider/save_as_raster_image_test.dart @@ -104,6 +104,32 @@ void main() { verifyNoMoreInteractions(mockImageService); verifyNoMoreInteractions(mockPhotoLibraryService); }); + + // test('When format is ora', () async { + // final expectedFilename = '$testName.ora'; + // when(mockImageService.exportAsPng(any)) + // .thenAnswer((_) async => Ok(fakeBytes)); + // when(mockImageService.exportAsJpg(any, any)) + // .thenAnswer((_) async => Ok(fakeBytes)); + // when(mockImageService.exportAsOra(any)) + // .thenAnswer((_) async => Ok(fakeBytes)); + // when(mockPermissionService.requestAccessForSavingToPhotos()) + // .thenAnswer((_) async => true); + // when(mockPhotoLibraryService.save(any, any)) + // .thenAnswer((_) async => const Ok(unit)); + // final testMetaData = OraMetaData(testName); + // final result = await sut(testMetaData, fakeImage); + + // expect(result, const Ok(unit)); + + // verify(mockPermissionService.requestAccessForSavingToPhotos()); + // verify(mockImageService.exportAsOra(fakeImage)); + // verify(mockPhotoLibraryService.save(expectedFilename, fakeBytes)); + + // verifyNoMoreInteractions(mockPermissionService); + // verifyNoMoreInteractions(mockImageService); + // verifyNoMoreInteractions(mockPhotoLibraryService); + // }); }, ); diff --git a/test/unit/provider/save_as_raster_image_test.mocks.dart b/test/unit/provider/save_as_raster_image_test.mocks.dart index 588d1a84..e0ccf037 100644 --- a/test/unit/provider/save_as_raster_image_test.mocks.dart +++ b/test/unit/provider/save_as_raster_image_test.mocks.dart @@ -118,6 +118,24 @@ class MockIImageService extends _i1.Mock implements _i3.IImageService { )), ) as _i4.Future<_i2.Result<_i7.Uint8List, _i6.Failure>>); + @override + _i4.Future<_i2.Result<_i7.Uint8List, _i6.Failure>> exportAsOra( + _i5.Image? image) => + (super.noSuchMethod( + Invocation.method( + #exportAsOra, + [image], + ), + returnValue: _i4.Future<_i2.Result<_i7.Uint8List, _i6.Failure>>.value( + _FakeResult_0<_i7.Uint8List, _i6.Failure>( + this, + Invocation.method( + #exportAsOra, + [image], + ), + )), + ) as _i4.Future<_i2.Result<_i7.Uint8List, _i6.Failure>>); + @override _i2.Result<_i7.Uint8List, _i6.Failure> getProjectPreview(String? path) => (super.noSuchMethod( diff --git a/test/utils/canvas_positions.dart b/test/utils/canvas_positions.dart index 57bad567..d2736417 100644 --- a/test/utils/canvas_positions.dart +++ b/test/utils/canvas_positions.dart @@ -1,3 +1,4 @@ +// Flutter imports: import 'package:flutter/cupertino.dart'; class CanvasPosition { diff --git a/test/utils/ui_interaction.dart b/test/utils/ui_interaction.dart index 7e51b7d1..249d6def 100644 --- a/test/utils/ui_interaction.dart +++ b/test/utils/ui_interaction.dart @@ -1,14 +1,15 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Package imports: import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:image/image.dart' as img; + // Project imports: import 'package:paintroid/app.dart'; import 'package:paintroid/core/providers/state/canvas_state_provider.dart'; import 'package:paintroid/core/providers/state/tools/toolbox/toolbox_state_provider.dart'; - import 'canvas_positions.dart'; import 'widget_finder.dart'; diff --git a/test/utils/widget_finder.dart b/test/utils/widget_finder.dart index ae2c736c..04b095e2 100644 --- a/test/utils/widget_finder.dart +++ b/test/utils/widget_finder.dart @@ -1,5 +1,10 @@ +// Flutter imports: import 'package:flutter/cupertino.dart'; + +// Package imports: import 'package:flutter_test/flutter_test.dart'; + +// Project imports: import 'package:paintroid/core/utils/widget_identifier.dart'; import 'package:paintroid/ui/pages/workspace_page/components/bottom_bar/bottom_nav_bar_items.dart'; import 'package:paintroid/ui/utils/top_bar_action_data.dart'; diff --git a/test/widget/landing_page/landing_page_test.mocks.dart b/test/widget/landing_page/landing_page_test.mocks.dart index 2937a373..94658a88 100644 --- a/test/widget/landing_page/landing_page_test.mocks.dart +++ b/test/widget/landing_page/landing_page_test.mocks.dart @@ -293,6 +293,24 @@ class MockIImageService extends _i1.Mock implements _i9.IImageService { )), ) as _i3.Future<_i5.Result<_i11.Uint8List, _i10.Failure>>); + @override + _i3.Future<_i5.Result<_i11.Uint8List, _i10.Failure>> exportAsOra( + _i6.Image? image) => + (super.noSuchMethod( + Invocation.method( + #exportAsOra, + [image], + ), + returnValue: _i3.Future<_i5.Result<_i11.Uint8List, _i10.Failure>>.value( + _FakeResult_3<_i11.Uint8List, _i10.Failure>( + this, + Invocation.method( + #exportAsOra, + [image], + ), + )), + ) as _i3.Future<_i5.Result<_i11.Uint8List, _i10.Failure>>); + @override _i5.Result<_i11.Uint8List, _i10.Failure> getProjectPreview(String? path) => (super.noSuchMethod( diff --git a/test/widget/workspace_page/bottom_control_navigation_bar_test.dart b/test/widget/workspace_page/bottom_control_navigation_bar_test.dart index d026f8c4..e3c04eb9 100644 --- a/test/widget/workspace_page/bottom_control_navigation_bar_test.dart +++ b/test/widget/workspace_page/bottom_control_navigation_bar_test.dart @@ -1,10 +1,12 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Package imports: import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; + // Project imports: import 'package:paintroid/core/localization/app_localizations.dart'; import 'package:paintroid/core/tools/tool_data.dart'; @@ -12,7 +14,6 @@ import 'package:paintroid/ui/pages/workspace_page/components/bottom_bar/tool_opt import 'package:paintroid/ui/pages/workspace_page/components/bottom_bar/tool_options/stroke_width_tool_option.dart'; import 'package:paintroid/ui/pages/workspace_page/workspace_page.dart'; import 'package:paintroid/ui/theme/theme.dart'; - import '../../utils/bottom_nav_bar_interactions.dart'; void main() { diff --git a/test/widget/workspace_page/eraser_tool_test.dart b/test/widget/workspace_page/eraser_tool_test.dart index ba6698f4..9468fe68 100644 --- a/test/widget/workspace_page/eraser_tool_test.dart +++ b/test/widget/workspace_page/eraser_tool_test.dart @@ -1,17 +1,18 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Package imports: import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; + // Project imports: import 'package:paintroid/core/localization/app_localizations.dart'; import 'package:paintroid/core/providers/object/device_service.dart'; import 'package:paintroid/core/tools/tool_data.dart'; import 'package:paintroid/ui/pages/workspace_page/workspace_page.dart'; import 'package:paintroid/ui/theme/theme.dart'; - import '../../utils/test_utils.dart'; void main() { diff --git a/test/widget/workspace_page/hand_tool_test.dart b/test/widget/workspace_page/hand_tool_test.dart index ab0ec7f7..1d402152 100644 --- a/test/widget/workspace_page/hand_tool_test.dart +++ b/test/widget/workspace_page/hand_tool_test.dart @@ -1,17 +1,18 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Package imports: import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; + // Project imports: import 'package:paintroid/core/localization/app_localizations.dart'; import 'package:paintroid/core/providers/object/device_service.dart'; import 'package:paintroid/core/tools/tool_data.dart'; import 'package:paintroid/ui/pages/workspace_page/workspace_page.dart'; import 'package:paintroid/ui/theme/theme.dart'; - import '../../utils/test_utils.dart'; void main() { diff --git a/test/widget/workspace_page/line_tool_test.dart b/test/widget/workspace_page/line_tool_test.dart index 8458cc5b..0abd0f89 100644 --- a/test/widget/workspace_page/line_tool_test.dart +++ b/test/widget/workspace_page/line_tool_test.dart @@ -1,13 +1,14 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Package imports: import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; + // Project imports: import 'package:paintroid/app.dart'; import 'package:paintroid/core/tools/tool_data.dart'; - import '../../utils/test_utils.dart'; void main() {