|  |  | @ -17,6 +17,7 @@ import org.thoughtcrime.securesms.imageeditor.Bounds; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.thoughtcrime.securesms.imageeditor.ColorableRenderer; |  |  |  | import org.thoughtcrime.securesms.imageeditor.ColorableRenderer; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.thoughtcrime.securesms.imageeditor.Renderer; |  |  |  | import org.thoughtcrime.securesms.imageeditor.Renderer; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.thoughtcrime.securesms.imageeditor.RendererContext; |  |  |  | import org.thoughtcrime.securesms.imageeditor.RendererContext; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import org.thoughtcrime.securesms.imageeditor.UndoRedoStackListener; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.util.HashMap; |  |  |  | import java.util.HashMap; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.util.LinkedHashSet; |  |  |  | import java.util.LinkedHashSet; | 
			
		
	
	
		
		
			
				
					|  |  | @ -42,6 +43,8 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  |   @NonNull |  |  |  |   @NonNull | 
			
		
	
		
		
			
				
					
					|  |  |  |   private Runnable invalidate = NULL_RUNNABLE; |  |  |  |   private Runnable invalidate = NULL_RUNNABLE; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   private UndoRedoStackListener undoRedoStackListener; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   private final UndoRedoStacks undoRedoStacks; |  |  |  |   private final UndoRedoStacks undoRedoStacks; | 
			
		
	
		
		
			
				
					
					|  |  |  |   private final UndoRedoStacks cropUndoRedoStacks; |  |  |  |   private final UndoRedoStacks cropUndoRedoStacks; | 
			
		
	
		
		
			
				
					
					|  |  |  |   private final InBoundsMemory inBoundsMemory = new InBoundsMemory(); |  |  |  |   private final InBoundsMemory inBoundsMemory = new InBoundsMemory(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -70,6 +73,10 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.invalidate = invalidate != null ? invalidate : NULL_RUNNABLE; |  |  |  |     this.invalidate = invalidate != null ? invalidate : NULL_RUNNABLE; | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   public void setUndoRedoStackListener(UndoRedoStackListener undoRedoStackListener) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     this.undoRedoStackListener = undoRedoStackListener; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   /** |  |  |  |   /** | 
			
		
	
		
		
			
				
					
					|  |  |  |    * Renders tree with the following matrix: |  |  |  |    * Renders tree with the following matrix: | 
			
		
	
		
		
			
				
					
					|  |  |  |    * <p> |  |  |  |    * <p> | 
			
		
	
	
		
		
			
				
					|  |  | @ -117,9 +124,7 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     UndoRedoStacks stacks = cropping ? cropUndoRedoStacks : undoRedoStacks; |  |  |  |     UndoRedoStacks stacks = cropping ? cropUndoRedoStacks : undoRedoStacks; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (stacks.getUndoStack().tryPush(editorElementHierarchy.getRoot())) { |  |  |  |     stacks.pushState(editorElementHierarchy.getRoot()); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       stacks.getRedoStack().clear(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   public void undo() { |  |  |  |   public void undo() { | 
			
		
	
	
		
		
			
				
					|  |  | @ -127,6 +132,8 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  |     UndoRedoStacks stacks   = cropping ? cropUndoRedoStacks : undoRedoStacks; |  |  |  |     UndoRedoStacks stacks   = cropping ? cropUndoRedoStacks : undoRedoStacks; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     undoRedo(stacks.getUndoStack(), stacks.getRedoStack(), cropping); |  |  |  |     undoRedo(stacks.getUndoStack(), stacks.getRedoStack(), cropping); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     updateUndoRedoAvailableState(stacks); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   public void redo() { |  |  |  |   public void redo() { | 
			
		
	
	
		
		
			
				
					|  |  | @ -134,12 +141,15 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  |     UndoRedoStacks stacks   = cropping ? cropUndoRedoStacks : undoRedoStacks; |  |  |  |     UndoRedoStacks stacks   = cropping ? cropUndoRedoStacks : undoRedoStacks; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     undoRedo(stacks.getRedoStack(), stacks.getUndoStack(), cropping); |  |  |  |     undoRedo(stacks.getRedoStack(), stacks.getUndoStack(), cropping); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     updateUndoRedoAvailableState(stacks); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   private void undoRedo(@NonNull ElementStack fromStack, @NonNull ElementStack toStack, boolean keepEditorState) { |  |  |  |   private void undoRedo(@NonNull ElementStack fromStack, @NonNull ElementStack toStack, boolean keepEditorState) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     final EditorElement popped = fromStack.pop(); |  |  |  |     final EditorElement oldRootElement = editorElementHierarchy.getRoot(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     final EditorElement popped         = fromStack.pop(oldRootElement); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (popped != null) { |  |  |  |     if (popped != null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       EditorElement oldRootElement = editorElementHierarchy.getRoot(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       editorElementHierarchy = EditorElementHierarchy.create(popped); |  |  |  |       editorElementHierarchy = EditorElementHierarchy.create(popped); | 
			
		
	
		
		
			
				
					
					|  |  |  |       toStack.tryPush(oldRootElement); |  |  |  |       toStack.tryPush(oldRootElement); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -187,6 +197,14 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   private void updateUndoRedoAvailableState(UndoRedoStacks currentStack) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (undoRedoStackListener == null) return; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     EditorElement root = editorElementHierarchy.getRoot(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     undoRedoStackListener.onAvailabilityChanged(currentStack.canUndo(root), currentStack.canRedo(root)); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   private static Map<UUID, EditorElement> getElementMap(@NonNull EditorElement element) { |  |  |  |   private static Map<UUID, EditorElement> getElementMap(@NonNull EditorElement element) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     final Map<UUID, EditorElement> result = new HashMap<>(); |  |  |  |     final Map<UUID, EditorElement> result = new HashMap<>(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     element.buildMap(result); |  |  |  |     element.buildMap(result); | 
			
		
	
	
		
		
			
				
					|  |  | @ -195,14 +213,15 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   public void startCrop() { |  |  |  |   public void startCrop() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     pushUndoPoint(); |  |  |  |     pushUndoPoint(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     cropUndoRedoStacks.getUndoStack().clear(); |  |  |  |     cropUndoRedoStacks.clear(editorElementHierarchy.getRoot()); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     cropUndoRedoStacks.getUndoStack().clear(); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     editorElementHierarchy.startCrop(invalidate); |  |  |  |     editorElementHierarchy.startCrop(invalidate); | 
			
		
	
		
		
			
				
					
					|  |  |  |     inBoundsMemory.push(editorElementHierarchy.getMainImage(), editorElementHierarchy.getCropEditorElement()); |  |  |  |     inBoundsMemory.push(editorElementHierarchy.getMainImage(), editorElementHierarchy.getCropEditorElement()); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     updateUndoRedoAvailableState(cropUndoRedoStacks); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   public void doneCrop() { |  |  |  |   public void doneCrop() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     editorElementHierarchy.doneCrop(visibleViewPort, invalidate); |  |  |  |     editorElementHierarchy.doneCrop(visibleViewPort, invalidate); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     updateUndoRedoAvailableState(undoRedoStacks); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   public void setCropAspectLock(boolean locked) { |  |  |  |   public void setCropAspectLock(boolean locked) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -223,6 +242,9 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (isCropping()) { |  |  |  |     if (isCropping()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       ensureFitsBounds(allowScaleToRepairCrop); |  |  |  |       ensureFitsBounds(allowScaleToRepairCrop); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     UndoRedoStacks stacks = isCropping() ? cropUndoRedoStacks : undoRedoStacks; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     updateUndoRedoAvailableState(stacks); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   private void ensureFitsBounds(boolean allowScaleToRepairCrop) { |  |  |  |   private void ensureFitsBounds(boolean allowScaleToRepairCrop) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -467,13 +489,14 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  |     parent.addElement(element); |  |  |  |     parent.addElement(element); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (parent != mainImage) { |  |  |  |     if (parent != mainImage) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       undoRedoStacks.getUndoStack().clear(); |  |  |  |       undoRedoStacks.clear(editorElementHierarchy.getRoot()); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     updateUndoRedoAvailableState(undoRedoStacks); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   public boolean isChanged() { |  |  |  |   public boolean isChanged() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     ElementStack undoStack = undoRedoStacks.getUndoStack(); |  |  |  |     return undoRedoStacks.isChanged(editorElementHierarchy.getRoot()); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     return !undoStack.isEmpty() || undoStack.isOverflowed(); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   public RectF findCropRelativeToRoot() { |  |  |  |   public RectF findCropRelativeToRoot() { | 
			
		
	
	
		
		
			
				
					|  |  | @ -578,4 +601,5 @@ public final class EditorModel implements Parcelable, RendererContext.Ready { | 
			
		
	
		
		
			
				
					
					|  |  |  |   public boolean isCropping() { |  |  |  |   public boolean isCropping() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     return editorElementHierarchy.getCropEditorElement().getFlags().isVisible(); |  |  |  |     return editorElementHierarchy.getCropEditorElement().getFlags().isVisible(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |