Skip to content

Commit

Permalink
merge: pull request #355 from hm21:dev
Browse files Browse the repository at this point in the history
feat: refine export logic, enhance history management, and improve text editing
  • Loading branch information
hm21 authored Feb 11, 2025
2 parents ce73332 + b3803ae commit edb427f
Show file tree
Hide file tree
Showing 12 changed files with 210 additions and 48 deletions.
26 changes: 18 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
# Changelog

# 8.1.6
## 8.1.9
- **FIX**(text-editor): Ensure text editor layer scales correctly when editing.
Added `enableMainEditorZoomFactor` to `textEditorConfigs` to apply the zoom factor in the text editor as well. Resolves [#349](https://github.com/hm21/pro_image_editor/issues/349).

## 8.1.8
- **FIX**(export): Ensure filters, tune adjustments, and blur configs are exported for `ExportHistorySpan.current` and `ExportHistorySpan.currentAndForward`.

## 8.1.7
- **FEAT**(MainEditorConfigs): Add `enableEscapeButton` to enable or disable the escape button listener.

## 8.1.6
- **FEAT**(layer): Add meta field to layermodels for custom metadata in export/import.

# 8.1.5
## 8.1.5
- **FEAT**(export): Optimize the export process by including only parameters that were modified in tune adjustments. This reduces the exported file size.

# 8.1.4
## 8.1.4
- **FIX**(generation): Use `captureOnlyBackgroundImageArea` instead of `captureOnlyDrawingBounds` for background cropping.

# 8.1.3
## 8.1.3
- **PERF**(capture-image): Improved image capture performance by minimizing its impact on the main thread.

# 8.1.2
## 8.1.2
- **FIX**(paint-editor): Ensure bottombar selection updates in UI when changed.
- **FIX**(paint-editor): Correct appBar canRedo to use the proper function instead of canUndo.
- **FIX**(layer): Resolve issue where selecting layers that overlap did not function as expected. Resolves issue [#282](https://github.com/hm21/pro_image_editor/issues/282)
- **FIX**(import): Resolve issue where transformations exported from the crop-rotate editor were not properly imported.

# 8.1.1
## 8.1.1
- **FIX**(crop_rotate_editor): Fixed an issue where the crop-rotate editor would throw multiple errors when reopened. Resolves issue [#236](https://github.com/hm21/pro_image_editor/issues/236) and [#237](https://github.com/hm21/pro_image_editor/issues/237).
- **PERF**(mediaquery): Replaces MediaQuery.of(...) with MediaQuery.sizeOf(...) to optimize performance and minimize unnecessary widget rebuilds.

# 8.1.0
## 8.1.0
- **FEAT**(layer): Added new methods `lockAllLayers` and `unlockAllLayers` to the main editor, enabling direct locking or unlocking of all layers.

# 8.0.4
## 8.0.4
- **FIX**(export/import): Resolve an issue where exported stickers within the JSON file could no longer be imported. Resolves issue [#334](https://github.com/hm21/pro_image_editor/issues/334)

## 8.0.3
Expand Down
2 changes: 1 addition & 1 deletion example/lib/features/import_export_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class _ImportExportExampleState extends State<ImportExportExample>
var history = await editor.exportStateHistory(
configs: const ExportEditorConfigs(
historySpan:
ExportHistorySpan.currentAndBackward
ExportHistorySpan.currentAndForward
// configs...
),
);
Expand Down
10 changes: 10 additions & 0 deletions lib/core/models/editor_configs/main_editor_configs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class MainEditorConfigs {
const MainEditorConfigs({
this.enableZoom = false,
this.enableCloseButton = true,
this.enableEscapeButton = true,
this.editorMinScale = 1.0,
this.editorMaxScale = 5.0,
this.transformSetup,
Expand All @@ -27,6 +28,13 @@ class MainEditorConfigs {
/// Determines whether the close button is displayed on the widget.
final bool enableCloseButton;

/// A boolean flag to enable or disable the escape button functionality.
///
/// When set to `true`, the escape button will be enabled, allowing users
/// to exit the editor or perform a specific action when the escape button
/// is pressed. When set to `false`, the escape button will be disabled.
final bool enableEscapeButton;

/// {@template enableZoom}
/// Indicates whether the editor supports zoom functionality.
///
Expand Down Expand Up @@ -98,6 +106,7 @@ class MainEditorConfigs {
/// others unchanged.
MainEditorConfigs copyWith({
bool? enableCloseButton,
bool? enableEscapeButton,
bool? enableZoom,
double? editorMinScale,
double? editorMaxScale,
Expand All @@ -109,6 +118,7 @@ class MainEditorConfigs {
}) {
return MainEditorConfigs(
enableCloseButton: enableCloseButton ?? this.enableCloseButton,
enableEscapeButton: enableEscapeButton ?? this.enableEscapeButton,
enableZoom: enableZoom ?? this.enableZoom,
editorMinScale: editorMinScale ?? this.editorMinScale,
editorMaxScale: editorMaxScale ?? this.editorMaxScale,
Expand Down
8 changes: 8 additions & 0 deletions lib/core/models/editor_configs/text_editor_configs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class TextEditorConfigs {
this.canToggleTextAlign = true,
this.canToggleBackgroundMode = true,
this.canChangeFontScale = true,
this.enableMainEditorZoomFactor = false,
this.initFontSize = 24.0,
this.initialTextAlign = TextAlign.center,
this.initFontScale = 1.0,
Expand Down Expand Up @@ -74,6 +75,10 @@ class TextEditorConfigs {
/// Determines if the background mode can be toggled.
final bool canToggleBackgroundMode;

/// A flag to enable or disable scaling of the text field in sync with the
/// editor's zoom level.
final bool enableMainEditorZoomFactor;

/// The initial font size for text.
final double initFontSize;

Expand Down Expand Up @@ -144,6 +149,7 @@ class TextEditorConfigs {
bool? canChangeFontScale,
bool? showSelectFontStyleBottomBar,
bool? canToggleBackgroundMode,
bool? enableMainEditorZoomFactor,
double? initFontSize,
TextAlign? initialTextAlign,
double? initFontScale,
Expand All @@ -170,6 +176,8 @@ class TextEditorConfigs {
showSelectFontStyleBottomBar ?? this.showSelectFontStyleBottomBar,
canToggleBackgroundMode:
canToggleBackgroundMode ?? this.canToggleBackgroundMode,
enableMainEditorZoomFactor:
enableMainEditorZoomFactor ?? this.enableMainEditorZoomFactor,
initFontSize: initFontSize ?? this.initFontSize,
initialTextAlign: initialTextAlign ?? this.initialTextAlign,
initFontScale: initFontScale ?? this.initFontScale,
Expand Down
46 changes: 46 additions & 0 deletions lib/core/models/history/state_history.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// Project imports:
import 'package:flutter/foundation.dart';

import '/features/crop_rotate_editor/models/transform_factors.dart';
import '/features/filter_editor/types/filter_matrix.dart';
import '/features/tune_editor/models/tune_adjustment_matrix.dart';
Expand Down Expand Up @@ -34,4 +36,48 @@ class EditorStateHistory {

/// The transformation from the crop/ rotate editor.
TransformConfigs? transformConfigs;

/// Creates a copy of the current `EditorStateHistory` instance with the
/// option to override some of its properties.
///
/// If a property is not provided, the current value of that property will be
/// used in the copied instance.
///
/// Returns a new `EditorStateHistory` instance with the updated properties.
EditorStateHistory copyWith({
double? blur,
List<Layer>? layers,
FilterMatrix? filters,
List<TuneAdjustmentMatrix>? tuneAdjustments,
TransformConfigs? transformConfigs,
}) {
return EditorStateHistory(
blur: blur ?? this.blur,
layers: layers ?? this.layers,
filters: filters ?? this.filters,
tuneAdjustments: tuneAdjustments ?? this.tuneAdjustments,
transformConfigs: transformConfigs ?? this.transformConfigs,
);
}

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;

return other is EditorStateHistory &&
other.blur == blur &&
listEquals(other.layers, layers) &&
listEquals(other.filters, filters) &&
listEquals(other.tuneAdjustments, tuneAdjustments) &&
transformConfigs == other.transformConfigs;
}

@override
int get hashCode {
return blur.hashCode ^
layers.hashCode ^
filters.hashCode ^
tuneAdjustments.hashCode ^
transformConfigs.hashCode;
}
}
31 changes: 31 additions & 0 deletions lib/features/crop_rotate_editor/models/transform_factors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,37 @@ class TransformConfigs {
},
};
}

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;

return other is TransformConfigs &&
other.offset == offset &&
other.cropRect == cropRect &&
other.originalSize == originalSize &&
other.cropEditorScreenRatio == cropEditorScreenRatio &&
other.angle == angle &&
other.scaleUser == scaleUser &&
other.scaleRotation == scaleRotation &&
other.aspectRatio == aspectRatio &&
other.flipX == flipX &&
other.flipY == flipY;
}

@override
int get hashCode {
return offset.hashCode ^
angle.hashCode ^
cropRect.hashCode ^
originalSize.hashCode ^
cropEditorScreenRatio.hashCode ^
scaleUser.hashCode ^
scaleRotation.hashCode ^
aspectRatio.hashCode ^
flipX.hashCode ^
flipY.hashCode;
}
}

/// An enumeration representing the maximum side of an image.
Expand Down
4 changes: 4 additions & 0 deletions lib/features/main_editor/main_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,9 @@ class ProImageEditorState extends State<ProImageEditor>
configs: configs,
theme: _theme,
callbacks: callbacks,
scaleFactor: textEditorConfigs.enableMainEditorZoomFactor
? _interactiveViewer.currentState?.scaleFactor ?? 1.0
: 1.0,
),

/// Small Duration is important for a smooth hero animation
Expand Down Expand Up @@ -1250,6 +1253,7 @@ class ProImageEditorState extends State<ProImageEditor>
configs: configs,
theme: _theme,
callbacks: callbacks,
scaleFactor: _interactiveViewer.currentState?.scaleFactor ?? 1.0,
),
duration: duration,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ class DesktopInteractionManager {
if (event is KeyDownEvent) {
switch (key) {
case 'Escape':
onEscape();
if (configs.mainEditor.enableEscapeButton) {
onEscape();
}
break;

case 'Subtract':
Expand Down
9 changes: 9 additions & 0 deletions lib/features/text_editor/text_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class TextEditor extends StatefulWidget with SimpleConfigsAccess {
this.layer,
this.callbacks = const ProImageEditorCallbacks(),
this.configs = const ProImageEditorConfigs(),
this.scaleFactor = 1.0,
required this.theme,
});
@override
Expand All @@ -44,6 +45,13 @@ class TextEditor extends StatefulWidget with SimpleConfigsAccess {
/// The text layer data to be edited, if any.
final TextLayer? layer;

/// A factor by which the textfield is scaled.
///
/// This value is used to adjust the size of the text in the editor.
/// A value of 1.0 means no scaling, while values greater than 1.0
/// increase the size and values less than 1.0 decrease the size.
final double scaleFactor;

@override
createState() => TextEditorState();
}
Expand Down Expand Up @@ -445,6 +453,7 @@ class TextEditorState extends State<TextEditor>
align: align,
backgroundColor: _backgroundColor,
textCtrl: textCtrl,
scaleFactor: widget.scaleFactor,
focusNode: focusNode,
i18n: i18n.textEditor,
layer: widget.layer,
Expand Down
79 changes: 43 additions & 36 deletions lib/features/text_editor/widgets/text_editor_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class TextEditorInput extends StatelessWidget {
required this.selectedTextStyle,
required this.align,
required this.textFontSize,
required this.scaleFactor,
required this.textColor,
required this.backgroundColor,
required this.layer,
Expand Down Expand Up @@ -60,6 +61,9 @@ class TextEditorInput extends StatelessWidget {
/// The font size of the input text.
final double textFontSize;

/// The scale factor to transform the textfield
final double scaleFactor;

/// The color of the input text.
final Color textColor;

Expand Down Expand Up @@ -126,43 +130,46 @@ class TextEditorInput extends StatelessWidget {
}

Widget _buildInputField() {
return RoundedBackgroundTextField(
key: const ValueKey('rounded-background-text-editor-field'),
controller: textCtrl,
focusNode: focusNode,
onChanged: callbacks?.handleChanged,
onEditingComplete: callbacks?.handleEditingComplete,
onSubmitted: callbacks?.handleSubmitted,
autocorrect: configs.autocorrect,
enableSuggestions: configs.enableSuggestions,
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.newline,
textCapitalization: TextCapitalization.sentences,
textAlign: textCtrl.text.isEmpty ? TextAlign.center : align,
maxLines: null,
cursorColor: configs.style.inputCursorColor,
cursorHeight: textFontSize * 1.2,
scrollPhysics: const NeverScrollableScrollPhysics(),
hint: textCtrl.text.isEmpty ? i18n.inputHintText : '',
hintStyle: selectedTextStyle.copyWith(
color: configs.style.inputHintColor,
fontSize: textFontSize,
height: 1.35,
shadows: [],
),
backgroundColor: backgroundColor,
style: selectedTextStyle.copyWith(
color: textColor,
fontSize: textFontSize,
height: 1.35,
letterSpacing: 0,
decoration: TextDecoration.none,
shadows: [],
),
return Transform.scale(
scale: scaleFactor,
child: RoundedBackgroundTextField(
key: const ValueKey('rounded-background-text-editor-field'),
controller: textCtrl,
focusNode: focusNode,
onChanged: callbacks?.handleChanged,
onEditingComplete: callbacks?.handleEditingComplete,
onSubmitted: callbacks?.handleSubmitted,
autocorrect: configs.autocorrect,
enableSuggestions: configs.enableSuggestions,
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.newline,
textCapitalization: TextCapitalization.sentences,
textAlign: textCtrl.text.isEmpty ? TextAlign.center : align,
maxLines: null,
cursorColor: configs.style.inputCursorColor,
cursorHeight: textFontSize * 1.2,
scrollPhysics: const NeverScrollableScrollPhysics(),
hint: textCtrl.text.isEmpty ? i18n.inputHintText : '',
hintStyle: selectedTextStyle.copyWith(
color: configs.style.inputHintColor,
fontSize: textFontSize,
height: 1.35,
shadows: [],
),
backgroundColor: backgroundColor,
style: selectedTextStyle.copyWith(
color: textColor,
fontSize: textFontSize,
height: 1.35,
letterSpacing: 0,
decoration: TextDecoration.none,
shadows: [],
),

/// If we edit an layer we focus to the textfield after the
/// hero animation is done
autofocus: layer == null,
/// If we edit an layer we focus to the textfield after the
/// hero animation is done
autofocus: layer == null,
),
);
}
}
Loading

0 comments on commit edb427f

Please sign in to comment.