mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-24 10:35:19 +00:00
Image Editor - Allow undoing during croping.
This commit is contained in:
parent
95304fe001
commit
068ffc2167
@ -1,5 +1,7 @@
|
|||||||
package org.thoughtcrime.securesms.imageeditor.model;
|
package org.thoughtcrime.securesms.imageeditor.model;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flags for an {@link EditorElement}.
|
* Flags for an {@link EditorElement}.
|
||||||
* <p>
|
* <p>
|
||||||
@ -113,4 +115,9 @@ public final class EditorFlags {
|
|||||||
void restoreState(int flags) {
|
void restoreState(int flags) {
|
||||||
this.flags = flags;
|
this.flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void set(@NonNull EditorFlags from) {
|
||||||
|
this.persistedFlags = from.persistedFlags;
|
||||||
|
this.flags = from.flags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,8 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private Runnable invalidate = NULL_RUNNABLE;
|
private Runnable invalidate = NULL_RUNNABLE;
|
||||||
|
|
||||||
private final ElementStack undoStack;
|
private final UndoRedoStacks undoRedoStacks;
|
||||||
private final ElementStack redoStack;
|
private final UndoRedoStacks cropUndoRedoStacks;
|
||||||
|
|
||||||
private EditorElementHierarchy editorElementHierarchy;
|
private EditorElementHierarchy editorElementHierarchy;
|
||||||
|
|
||||||
@ -51,16 +51,16 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||||||
public EditorModel() {
|
public EditorModel() {
|
||||||
this.size = new Point(1024, 1024);
|
this.size = new Point(1024, 1024);
|
||||||
this.editorElementHierarchy = EditorElementHierarchy.create();
|
this.editorElementHierarchy = EditorElementHierarchy.create();
|
||||||
this.undoStack = new ElementStack(50);
|
this.undoRedoStacks = new UndoRedoStacks(50);
|
||||||
this.redoStack = new ElementStack(50);
|
this.cropUndoRedoStacks = new UndoRedoStacks(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
private EditorModel(Parcel in) {
|
private EditorModel(Parcel in) {
|
||||||
ClassLoader classLoader = getClass().getClassLoader();
|
ClassLoader classLoader = getClass().getClassLoader();
|
||||||
this.size = new Point(in.readInt(), in.readInt());
|
this.size = new Point(in.readInt(), in.readInt());
|
||||||
this.editorElementHierarchy = EditorElementHierarchy.create(in.readParcelable(classLoader));
|
this.editorElementHierarchy = EditorElementHierarchy.create(in.readParcelable(classLoader));
|
||||||
this.undoStack = in.readParcelable(classLoader);
|
this.undoRedoStacks = in.readParcelable(classLoader);
|
||||||
this.redoStack = in.readParcelable(classLoader);
|
this.cropUndoRedoStacks = in.readParcelable(classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInvalidate(@Nullable Runnable invalidate) {
|
public void setInvalidate(@Nullable Runnable invalidate) {
|
||||||
@ -107,28 +107,35 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void pushUndoPoint() {
|
public void pushUndoPoint() {
|
||||||
if (undoStack.tryPush(editorElementHierarchy.getRoot())) {
|
UndoRedoStacks stacks = isCropping() ? cropUndoRedoStacks : undoRedoStacks;
|
||||||
redoStack.clear();
|
|
||||||
|
if (stacks.getUndoStack().tryPush(editorElementHierarchy.getRoot())) {
|
||||||
|
stacks.getRedoStack().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void undo() {
|
public void undo() {
|
||||||
undoRedo(undoStack, redoStack);
|
boolean cropping = isCropping();
|
||||||
|
UndoRedoStacks stacks = cropping ? cropUndoRedoStacks : undoRedoStacks;
|
||||||
|
|
||||||
|
undoRedo(stacks.getUndoStack(), stacks.getRedoStack(), cropping);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void redo() {
|
public void redo() {
|
||||||
undoRedo(redoStack, undoStack);
|
boolean cropping = isCropping();
|
||||||
|
UndoRedoStacks stacks = cropping ? cropUndoRedoStacks : undoRedoStacks;
|
||||||
|
|
||||||
|
undoRedo(stacks.getRedoStack(), stacks.getUndoStack(), cropping);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void undoRedo(@NonNull ElementStack fromStack, @NonNull ElementStack toStack) {
|
private void undoRedo(@NonNull ElementStack fromStack, @NonNull ElementStack toStack, boolean keepEditorState) {
|
||||||
final EditorElement popped = fromStack.pop();
|
final EditorElement popped = fromStack.pop();
|
||||||
|
|
||||||
if (popped != null) {
|
if (popped != null) {
|
||||||
EditorElement oldRootElement = editorElementHierarchy.getRoot();
|
EditorElement oldRootElement = editorElementHierarchy.getRoot();
|
||||||
editorElementHierarchy = EditorElementHierarchy.create(popped);
|
editorElementHierarchy = EditorElementHierarchy.create(popped);
|
||||||
toStack.tryPush(oldRootElement);
|
toStack.tryPush(oldRootElement);
|
||||||
|
|
||||||
restoreStateWithAnimations(oldRootElement, editorElementHierarchy.getRoot(), invalidate);
|
restoreStateWithAnimations(oldRootElement, editorElementHierarchy.getRoot(), invalidate, keepEditorState);
|
||||||
invalidate.run();
|
invalidate.run();
|
||||||
|
|
||||||
// re-zoom image root as the view port might be different now
|
// re-zoom image root as the view port might be different now
|
||||||
@ -136,7 +143,7 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void restoreStateWithAnimations(@NonNull EditorElement fromRootElement, @NonNull EditorElement toRootElement, @NonNull Runnable onInvalidate) {
|
private static void restoreStateWithAnimations(@NonNull EditorElement fromRootElement, @NonNull EditorElement toRootElement, @NonNull Runnable onInvalidate, boolean keepEditorState) {
|
||||||
Map<UUID, EditorElement> fromMap = getElementMap(fromRootElement);
|
Map<UUID, EditorElement> fromMap = getElementMap(fromRootElement);
|
||||||
Map<UUID, EditorElement> toMap = getElementMap(toRootElement);
|
Map<UUID, EditorElement> toMap = getElementMap(toRootElement);
|
||||||
|
|
||||||
@ -145,6 +152,11 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||||||
EditorElement toElement = toMap.get(fromElement.getId());
|
EditorElement toElement = toMap.get(fromElement.getId());
|
||||||
if (toElement != null) {
|
if (toElement != null) {
|
||||||
toElement.animateFrom(fromElement.getLocalMatrixAnimating(), onInvalidate);
|
toElement.animateFrom(fromElement.getLocalMatrixAnimating(), onInvalidate);
|
||||||
|
|
||||||
|
if (keepEditorState) {
|
||||||
|
toElement.getEditorMatrix().set(fromElement.getEditorMatrix());
|
||||||
|
toElement.getFlags().set(fromElement.getFlags());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// element is removed
|
// element is removed
|
||||||
EditorElement parentFrom = fromRootElement.parentOf(fromElement);
|
EditorElement parentFrom = fromRootElement.parentOf(fromElement);
|
||||||
@ -173,6 +185,8 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||||||
|
|
||||||
public void startCrop() {
|
public void startCrop() {
|
||||||
pushUndoPoint();
|
pushUndoPoint();
|
||||||
|
cropUndoRedoStacks.getUndoStack().clear();
|
||||||
|
cropUndoRedoStacks.getUndoStack().clear();
|
||||||
editorElementHierarchy.startCrop(invalidate);
|
editorElementHierarchy.startCrop(invalidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,8 +250,8 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||||||
dest.writeInt(size.x);
|
dest.writeInt(size.x);
|
||||||
dest.writeInt(size.y);
|
dest.writeInt(size.y);
|
||||||
dest.writeParcelable(editorElementHierarchy.getRoot(), flags);
|
dest.writeParcelable(editorElementHierarchy.getRoot(), flags);
|
||||||
dest.writeParcelable(undoStack, flags);
|
dest.writeParcelable(undoRedoStacks, flags);
|
||||||
dest.writeParcelable(redoStack, flags);
|
dest.writeParcelable(cropUndoRedoStacks, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -337,11 +351,12 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||||||
parent.addElement(element);
|
parent.addElement(element);
|
||||||
|
|
||||||
if (parent != mainImage) {
|
if (parent != mainImage) {
|
||||||
undoStack.clear();
|
undoRedoStacks.getUndoStack().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isChanged() {
|
public boolean isChanged() {
|
||||||
|
ElementStack undoStack = undoRedoStacks.getUndoStack();
|
||||||
return !undoStack.isEmpty() || undoStack.isOverflowed();
|
return !undoStack.isEmpty() || undoStack.isOverflowed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +396,7 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||||||
editorElementHierarchy.flipRotate(0, -1, 1, visibleViewPort, invalidate);
|
editorElementHierarchy.flipRotate(0, -1, 1, visibleViewPort, invalidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flipVerticle() {
|
public void flipVertical() {
|
||||||
pushUndoPoint();
|
pushUndoPoint();
|
||||||
editorElementHierarchy.flipRotate(0, 1, -1, visibleViewPort, invalidate);
|
editorElementHierarchy.flipRotate(0, 1, -1, visibleViewPort, invalidate);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
package org.thoughtcrime.securesms.imageeditor.model;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
final class UndoRedoStacks implements Parcelable {
|
||||||
|
|
||||||
|
private final ElementStack undoStack;
|
||||||
|
private final ElementStack redoStack;
|
||||||
|
|
||||||
|
public UndoRedoStacks(int limit) {
|
||||||
|
this(new ElementStack(limit), new ElementStack(limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
private UndoRedoStacks(ElementStack undoStack, ElementStack redoStack) {
|
||||||
|
this.undoStack = undoStack;
|
||||||
|
this.redoStack = redoStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<UndoRedoStacks> CREATOR = new Creator<UndoRedoStacks>() {
|
||||||
|
@Override
|
||||||
|
public UndoRedoStacks createFromParcel(Parcel in) {
|
||||||
|
return new UndoRedoStacks(
|
||||||
|
in.readParcelable(ElementStack.class.getClassLoader()),
|
||||||
|
in.readParcelable(ElementStack.class.getClassLoader())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UndoRedoStacks[] newArray(int size) {
|
||||||
|
return new UndoRedoStacks[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeParcelable(undoStack, flags);
|
||||||
|
dest.writeParcelable(redoStack, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementStack getUndoStack() {
|
||||||
|
return undoStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementStack getRedoStack() {
|
||||||
|
return redoStack;
|
||||||
|
}
|
||||||
|
}
|
@ -107,7 +107,7 @@ public final class ImageEditorHud extends LinearLayout {
|
|||||||
|
|
||||||
setVisibleViewsWhenInMode(Mode.MOVE_DELETE, confirmButton, deleteButton);
|
setVisibleViewsWhenInMode(Mode.MOVE_DELETE, confirmButton, deleteButton);
|
||||||
|
|
||||||
setVisibleViewsWhenInMode(Mode.CROP, confirmButton, cropFlipButton, cropRotateButton, cropAspectLock);
|
setVisibleViewsWhenInMode(Mode.CROP, confirmButton, cropFlipButton, cropRotateButton, cropAspectLock, undoButton);
|
||||||
|
|
||||||
for (Set<View> views : visibilityModeMap.values()) {
|
for (Set<View> views : visibilityModeMap.values()) {
|
||||||
allViews.addAll(views);
|
allViews.addAll(views);
|
||||||
|
Loading…
Reference in New Issue
Block a user