Skip to content

Commit b5b450f

Browse files
authored
merge: pull request #621 from hm21:dev
feat(state-history): track background image changes for undo/redo
2 parents 1bdfb84 + 4b5de8f commit b5b450f

File tree

5 files changed

+77
-40
lines changed

5 files changed

+77
-40
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## 11.2.0
4+
- **FEAT**(state-history): Added support for undo and redo when the background image is changed in the state history.
5+
36
## 11.1.3
47
- **FIX**(text-editor): Fixed an issue where long text didn’t wrap correctly.
58
- **FIX**(video-editor): Fixed display issues with the trim bar, especially for maximum and minimum durations.

example/lib/features/frame_example.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,11 @@ class _FrameExampleState extends State<FrameExample>
208208
await _createTransparentBackgroundImage();
209209

210210
/// Set the background bounds
211-
editorKey.currentState!.editorImage = EditorImage(
212-
byteArray: _transparentBytes,
211+
await editorKey.currentState!.updateBackgroundImage(
212+
EditorImage(byteArray: _transparentBytes),
213+
updateHistory: false,
213214
);
215+
214216
await editorKey.currentState!.decodeImage();
215217
}
216218

lib/features/main_editor/main_editor.dart

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ class ProImageEditorState extends State<ProImageEditor>
397397

398398
/// Manager class for managing the state of the editor.
399399
late final StateManager stateManager = StateManager(
400+
activeBackgroundImage: widget.editorImage,
400401
onStateHistoryChange: () =>
401402
mainEditorCallbacks?.onStateHistoryChange?.call(stateManager, this),
402403
);
@@ -513,7 +514,7 @@ class ProImageEditorState extends State<ProImageEditor>
513514
}
514515

515516
/// Get the current background image.
516-
late EditorImage? editorImage = widget.editorImage;
517+
EditorImage? get editorImage => stateManager.activeBackgroundImage;
517518

518519
/// A [Completer] used to track the completion of a page open operation.
519520
///
@@ -878,7 +879,7 @@ class ProImageEditorState extends State<ProImageEditor>
878879
);
879880

880881
final resolution = widget.videoController!.initialResolution;
881-
editorImage = EditorImage(
882+
stateManager.activeBackgroundImage = EditorImage(
882883
byteArray: await createTransparentImage(
883884
resolution.width,
884885
resolution.height,
@@ -994,43 +995,42 @@ class ProImageEditorState extends State<ProImageEditor>
994995
}
995996
}
996997

997-
/// Replace the background image with a new image and ensures all relevant
998-
/// states are rebuilt to reflect the new background. This includes marking
999-
/// all background screenshots as "broken" to trigger re-capture with the
1000-
/// new image, and rebuilding the current editor state to apply the changes.
1001-
///
1002-
/// The method performs the following steps:
1003-
/// 1. Updates the editor's background image.
1004-
/// 2. Decodes the new image to prepare it for rendering.
1005-
/// 3. Marks all screenshots as "broken" so they are recaptured with the
1006-
/// updated background.
1007-
/// 4. Rebuilds the current editor state to ensure the new background is
1008-
/// applied.
1009-
Future<void> updateBackgroundImage(EditorImage image) async {
1010-
editorImage = image;
1011-
await decodeImage();
1012-
1013-
/// Mark all background captured images with the old background image as
1014-
/// "broken" that the editor capture them with the new image again
1015-
for (var item in stateManager.screenshots) {
1016-
item.broken = true;
998+
/// Updates the background image in the editor.
999+
///
1000+
/// If [updateHistory] is `false`, marks all background-captured images that
1001+
/// use the old-background image as "broken" so they will be recaptured with
1002+
/// the new image, and set the active background image to [image].
1003+
///
1004+
/// If [updateHistory] is `true`, updates the background images in the
1005+
/// state manager, replaces the old image with [image], and adds the change
1006+
/// to the history.
1007+
///
1008+
/// After updating, decodes the new image asynchronously.
1009+
///
1010+
/// [image]: The new background image to set.
1011+
/// [updateHistory]: Whether to update the history with this change
1012+
/// (default is `true`).
1013+
Future<void> updateBackgroundImage(
1014+
EditorImage image, {
1015+
bool updateHistory = true,
1016+
}) async {
1017+
if (!updateHistory) {
1018+
/// Mark all background-captured images that use the old background
1019+
/// image as "broken" so the editor captures them again with the new
1020+
/// image.
1021+
for (var item in stateManager.screenshots) {
1022+
item.broken = true;
1023+
}
1024+
stateManager.activeBackgroundImage = image;
1025+
} else {
1026+
stateManager.updateBackgroundImages(
1027+
oldImage: editorImage ?? widget.editorImage!,
1028+
newImage: image,
1029+
);
1030+
addHistory();
10171031
}
10181032

1019-
/// Force to rebuild everything
1020-
int pos = stateManager.historyPointer;
1021-
EditorStateHistory oldHistory = stateManager.stateHistory[pos];
1022-
1023-
stateManager.stateHistory[pos] = EditorStateHistory(
1024-
layers: oldHistory.layers,
1025-
transformConfigs: oldHistory.transformConfigs,
1026-
blur: oldHistory.blur,
1027-
filters: [...oldHistory.filters],
1028-
tuneAdjustments: [...oldHistory.tuneAdjustments],
1029-
);
1030-
WidgetsBinding.instance.addPostFrameCallback((_) {
1031-
if (!mounted) return;
1032-
_backgroundImageColorFilterKey.currentState?.refresh();
1033-
});
1033+
await decodeImage();
10341034
}
10351035

10361036
@override

lib/features/main_editor/services/state_manager.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import '/core/models/editor_image.dart';
12
import '/core/models/history/state_history.dart';
23
import '/core/models/layers/layer.dart';
34
import '/core/models/multi_threading/thread_capture_model.dart';
@@ -10,6 +11,7 @@ class StateManager {
1011
/// Creates an instance of [StateManager].
1112
StateManager({
1213
required this.onStateHistoryChange,
14+
required this.activeBackgroundImage,
1315
});
1416

1517
/// Optional callbacks for additional editor actions.
@@ -47,6 +49,31 @@ class StateManager {
4749
/// for undo/redo functionality.
4850
List<EditorStateHistory> get stateHistory => _stateHistory;
4951

52+
final Map<int, EditorImage> _backgroundImages = {};
53+
54+
/// The currently active background image in the editor.
55+
EditorImage? activeBackgroundImage;
56+
57+
/// Updates the background images in the editor's history.
58+
///
59+
/// Replaces the background image at the current history pointer with
60+
/// [oldImage], and sets the next history entry to [newImage]. Also updates
61+
/// the [activeBackgroundImage] to [newImage].
62+
///
63+
/// Parameters:
64+
/// - [oldImage]: The previous background image to store at the current
65+
/// history pointer.
66+
/// - [newImage]: The new background image to store at the next history
67+
/// pointer.
68+
void updateBackgroundImages({
69+
required EditorImage oldImage,
70+
required EditorImage newImage,
71+
}) {
72+
_backgroundImages[historyPointer] = oldImage;
73+
_backgroundImages[historyPointer + 1] = newImage;
74+
activeBackgroundImage = newImage;
75+
}
76+
5077
/// A setter for updating the state history list.
5178
/// When a new list of editor states is assigned, it triggers
5279
/// `_updateActiveItems()` to refresh any dependent components based on the
@@ -103,6 +130,10 @@ class StateManager {
103130
0.0;
104131

105132
onStateHistoryChange?.call();
133+
134+
if (_backgroundImages[historyPointer] != null) {
135+
activeBackgroundImage = _backgroundImages[historyPointer];
136+
}
106137
}
107138

108139
/// A list of active filters applied to the image.
@@ -186,6 +217,7 @@ class StateManager {
186217
while (_historyPointer < screenshots.length) {
187218
screenshots.removeLast();
188219
}
220+
_backgroundImages.removeWhere((index, _) => index > _historyPointer);
189221
}
190222
_historyPointer = _stateHistory.length - 1;
191223
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: pro_image_editor
22
description: "A Flutter image editor: Seamlessly enhance your images with user-friendly editing features."
3-
version: 11.1.3
3+
version: 11.2.0
44
homepage: https://github.com/hm21/pro_image_editor/
55
repository: https://github.com/hm21/pro_image_editor/
66
documentation: https://github.com/hm21/pro_image_editor/

0 commit comments

Comments
 (0)