Skip to content
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
5 changes: 4 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<queries>
<intent>
Expand All @@ -23,7 +25,8 @@
<application
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:label="Pocket Paint">
android:label="Pocket Paint"
android:enableOnBackInvokedCallback="true">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
Expand Down
16 changes: 16 additions & 0 deletions lib/core/commands/command_factory/command_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clipboard_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/import_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/delete_region_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/text_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart';
Expand Down Expand Up @@ -77,6 +78,21 @@ class CommandFactory {
rotation,
);

ImportCommand createImportCommand(
Paint paint,
Uint8List imageData,
ui.Offset offset,
double scale,
double rotation,
) =>
ImportCommand(
paint,
imageData,
offset,
scale,
rotation,
);

TextCommand createTextCommand(
Offset point,
String text,
Expand Down
3 changes: 3 additions & 0 deletions lib/core/commands/command_implementation/command.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:equatable/equatable.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clipboard_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/import_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/delete_region_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/path_command.dart';
Expand Down Expand Up @@ -31,6 +32,8 @@ abstract class Command with EquatableMixin {
return EllipseShapeCommand.fromJson(json);
case SerializerType.CLIPBOARD_COMMAND:
return ClipboardCommand.fromJson(json);
case SerializerType.IMPORT_COMMAND:
return ImportCommand.fromJson(json);
case SerializerType.DELETE_REGION_COMMAND:
return DeleteRegionCommand.fromJson(json);
case SerializerType.TEXT_COMMAND:
Expand Down
122 changes: 122 additions & 0 deletions lib/core/commands/command_implementation/graphic/import_command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// ignore_for_file: must_be_immutable

import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/graphic_command.dart';
import 'package:paintroid/core/json_serialization/converter/offset_converter.dart';
import 'package:paintroid/core/json_serialization/converter/paint_converter.dart';
import 'package:paintroid/core/json_serialization/converter/uint8list_base64_converter.dart';
import 'package:paintroid/core/json_serialization/versioning/serializer_version.dart';
import 'package:paintroid/core/json_serialization/versioning/version_strategy.dart';
import 'package:paintroid/core/models/loggable_mixin.dart';
import 'package:toast/toast.dart';

part 'import_command.g.dart';

@JsonSerializable()
class ImportCommand extends GraphicCommand with LoggableMixin {
@Uint8ListBase64Converter()
final Uint8List imageData;
@OffsetConverter()
final ui.Offset offset;
final double scale;
final double rotation;

final int version;
final String type;

@JsonKey(includeFromJson: false, includeToJson: false)
ui.Image? _runtimeImage;

ImportCommand(
super.paint,
this.imageData,
this.offset,
this.scale,
this.rotation, {
int? version,
this.type = SerializerType.IMPORT_COMMAND,
}) : version = version ??
VersionStrategyManager.strategy.getImportCommandVersion();

@override
Future<void> prepareForRuntime() async {
if (_runtimeImage == null && imageData.isNotEmpty) {
try {
final buffer = await ui.ImmutableBuffer.fromUint8List(imageData);
final descriptor = await ui.ImageDescriptor.encoded(buffer);
final codec = await descriptor.instantiateCodec();
final frameInfo = await codec.getNextFrame();
_runtimeImage = frameInfo.image;
} catch (e, _) {
Toast.show(
'Error: $e',
duration: Toast.lengthShort,
gravity: Toast.bottom,
);
_runtimeImage = null;
}
}
}

@override
void call(ui.Canvas canvas) {
if (_runtimeImage == null) {
Toast.show(
'ImportCommand.call: _runtimeImage is null. Cannot draw.',
duration: Toast.lengthShort,
gravity: Toast.bottom,
);
return;
}

canvas.save();
canvas.translate(offset.dx, offset.dy);
canvas.rotate(rotation);
canvas.scale(scale);

final imageWidth = _runtimeImage!.width.toDouble();
final imageHeight = _runtimeImage!.height.toDouble();

final src = ui.Rect.fromLTWH(0, 0, imageWidth, imageHeight);
final dst = ui.Rect.fromLTWH(
-imageWidth / 2,
-imageHeight / 2,
imageWidth,
imageHeight,
);
final imagePaint = ui.Paint()..filterQuality = ui.FilterQuality.high;
canvas.drawImageRect(_runtimeImage!, src, dst, imagePaint);
canvas.restore();
}

@override
List<Object?> get props => [
paint,
imageData,
offset,
scale,
rotation,
version,
type,
];

@override
Map<String, dynamic> toJson() => _$ImportCommandToJson(this);

factory ImportCommand.fromJson(Map<String, dynamic> json) {
int version = json['version'] as int;

switch (version) {
case Version.v1:
return _$ImportCommandFromJson(json);
case Version.v2:
// For different versions of ImportCommand the deserialization
// has to be implemented manually.
// Autogenerated code can only be used for one version
default:
return _$ImportCommandFromJson(json);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions lib/core/commands/command_manager/command_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:ui';

import 'package:paintroid/core/commands/command_implementation/command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/clipboard_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/import_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/text_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/graphic_command.dart';
import 'package:paintroid/core/commands/command_implementation/graphic/line_command.dart';
Expand All @@ -25,6 +26,7 @@ class CommandManager {
final List<Command> _redoStack = [];

void addGraphicCommand(GraphicCommand command) {
_redoStack.clear();
_undoStack.add(command);
}

Expand Down Expand Up @@ -120,6 +122,8 @@ class CommandManager {
return ToolData.SHAPES;
} else if (command.runtimeType == ClipboardCommand) {
return ToolData.CLIPBOARD;
} else if (command.runtimeType == ImportCommand) {
return ToolData.IMPORT;
} else if (command.runtimeType == TextCommand) {
return ToolData.TEXT;
} else if (command.runtimeType == SprayCommand) {
Expand Down
29 changes: 19 additions & 10 deletions lib/core/commands/command_painter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:paintroid/core/providers/state/canvas_state_provider.dart';
import 'package:paintroid/core/providers/state/paint_provider.dart';
import 'package:paintroid/core/providers/state/toolbox_state_provider.dart';
import 'package:paintroid/core/tools/implementation/clipboard_tool.dart';
import 'package:paintroid/core/tools/implementation/import_tool.dart';
import 'package:paintroid/core/tools/implementation/cursor_tool.dart';
import 'package:paintroid/core/tools/implementation/shapes_tool.dart';
import 'package:paintroid/core/tools/implementation/text_tool.dart';
Expand All @@ -22,10 +23,11 @@ class CommandPainter extends CustomPainter {
final ui.Image? cachedImage;

CommandPainter(this.ref, {this.cachedImage})
: currentTool = ref.read(toolBoxStateProvider).currentTool,
commandManager = ref.read(commandManagerProvider),
isCachingCommand = ref.read(
canvasStateProvider.select((state) => state.isCachingCommand));
: currentTool = ref.read(toolBoxStateProvider).currentTool,
commandManager = ref.read(commandManagerProvider),
isCachingCommand = ref.read(
canvasStateProvider.select((state) => state.isCachingCommand),
);

final WidgetRef ref;

Expand All @@ -37,9 +39,10 @@ class CommandPainter extends CustomPainter {
canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height));
}

bool isEraserDrawing = currentTool.type == ToolType.ERASER &&
currentTool is BrushTool &&
((currentTool as BrushTool).isDrawing || isCachingCommand);
bool isEraserDrawing =
currentTool.type == ToolType.ERASER &&
currentTool is BrushTool &&
((currentTool as BrushTool).isDrawing || isCachingCommand);

if (isEraserDrawing) {
canvas.saveLayer(Rect.fromLTWH(0, 0, size.width, size.height), Paint());
Expand All @@ -60,11 +63,17 @@ class CommandPainter extends CustomPainter {
break;
case ToolType.CURSOR:
commandManager.executeLastCommand(canvas);
(currentTool as CursorTool)
.drawCursorIcon(canvas, ref.read(paintProvider));
(currentTool as CursorTool).drawCursorIcon(
canvas,
ref.read(paintProvider),
);
break;
case ToolType.CLIPBOARD:
(currentTool as ClipboardTool).paint(canvas, size);
break;
case ToolType.IMPORT:
(currentTool as ImportTool).paint(canvas, size);
break;
case ToolType.TEXT:
(currentTool as TextTool).drawGuides(canvas, ref.read(paintProvider));
break;
Expand All @@ -78,7 +87,7 @@ class CommandPainter extends CustomPainter {
}
break;
}

if (isEraserDrawing) {
canvas.restore();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class SerializerVersion {
static const int HEART_SHAPE_COMMAND_VERSION = Version.v1;
static const int SPRAY_COMMAND_VERSION = Version.v1;
static const int CLIPBOARD_COMMAND_VERSION = Version.v1;
static const int IMPORT_COMMAND_VERSION = Version.v1;
static const int DELETE_REGION_COMMAND_VERSION = Version.v1;
static const int COLOR_CHANGED_COMMAND_VERSION = Version.v1;
}
Expand All @@ -33,6 +34,7 @@ class SerializerType {
static const String HEART_SHAPE_COMMAND = 'HeartShapeCommand';
static const String SPRAY_COMMAND = 'SprayCommand';
static const String CLIPBOARD_COMMAND = 'ClipboardCommand';
static const String IMPORT_COMMAND = 'ImportCommand';
static const String DELETE_REGION_COMMAND = 'DeleteRegionCommand';
static const String COLOR_CHANGED_COMMAND = 'ColorChangedCommand';
}
5 changes: 5 additions & 0 deletions lib/core/json_serialization/versioning/version_strategy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ abstract class IVersionStrategy {

int getClipboardCommandVersion();

int getImportCommandVersion();

int getDeleteRegionCommandVersion();

int getColorChangedCommandVersion();
Expand Down Expand Up @@ -62,6 +64,9 @@ class ProductionVersionStrategy implements IVersionStrategy {
int getClipboardCommandVersion() =>
SerializerVersion.CLIPBOARD_COMMAND_VERSION;

@override
int getImportCommandVersion() => SerializerVersion.IMPORT_COMMAND_VERSION;

@override
int getDeleteRegionCommandVersion() =>
SerializerVersion.DELETE_REGION_COMMAND_VERSION;
Expand Down
Loading
Loading