Improve trash can using in-renderer object.
This commit is contained in:
parent
e7833df539
commit
1f7b1d91c4
7 changed files with 250 additions and 100 deletions
|
@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.imageeditor.model.EditorModel;
|
|||
import org.thoughtcrime.securesms.imageeditor.model.ThumbRenderer;
|
||||
import org.thoughtcrime.securesms.imageeditor.renderers.BezierDrawingRenderer;
|
||||
import org.thoughtcrime.securesms.imageeditor.renderers.MultiLineTextRenderer;
|
||||
import org.thoughtcrime.securesms.imageeditor.renderers.TrashRenderer;
|
||||
|
||||
/**
|
||||
* ImageEditorView
|
||||
|
@ -231,6 +232,7 @@ public final class ImageEditorView extends FrameLayout {
|
|||
editSession = startEdit(inverse, point, selected);
|
||||
|
||||
if (editSession != null) {
|
||||
checkTrashIntersect(point);
|
||||
notifyDragStart(editSession.getSelected());
|
||||
}
|
||||
|
||||
|
@ -260,7 +262,7 @@ public final class ImageEditorView extends FrameLayout {
|
|||
}
|
||||
model.moving(editSession.getSelected());
|
||||
invalidate();
|
||||
notifyDragMove(editSession.getSelected(), event);
|
||||
notifyDragMove(editSession.getSelected(), checkTrashIntersect(getPoint(event)));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -304,7 +306,7 @@ public final class ImageEditorView extends FrameLayout {
|
|||
if (editSession != null) {
|
||||
editSession.commit();
|
||||
dragDropRelease(false);
|
||||
notifyDragEnd(editSession.getSelected());
|
||||
notifyDragEnd(editSession.getSelected(), checkTrashIntersect(getPoint(event)));
|
||||
|
||||
editSession = null;
|
||||
model.postEdit(moreThanOnePointerUsedInSession);
|
||||
|
@ -320,21 +322,35 @@ public final class ImageEditorView extends FrameLayout {
|
|||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
private boolean checkTrashIntersect(@NonNull PointF point) {
|
||||
if (mode == Mode.Draw || mode == Mode.Blur) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (model.checkTrashIntersectsPoint(point, viewMatrix)) {
|
||||
((TrashRenderer) model.getTrash().getRenderer()).expand();
|
||||
return true;
|
||||
} else {
|
||||
((TrashRenderer) model.getTrash().getRenderer()).shrink();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyDragStart(@Nullable EditorElement editorElement) {
|
||||
if (dragListener != null) {
|
||||
dragListener.onDragStarted(editorElement);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyDragMove(@Nullable EditorElement editorElement, @NonNull MotionEvent event) {
|
||||
private void notifyDragMove(@Nullable EditorElement editorElement, boolean isInTrashHitZone) {
|
||||
if (dragListener != null) {
|
||||
dragListener.onDragMoved(editorElement, event);
|
||||
dragListener.onDragMoved(editorElement, isInTrashHitZone);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyDragEnd(@Nullable EditorElement editorElement) {
|
||||
private void notifyDragEnd(@Nullable EditorElement editorElement, boolean isInTrashHitZone) {
|
||||
if (dragListener != null) {
|
||||
dragListener.onDragEnded(editorElement);
|
||||
dragListener.onDragEnded(editorElement, isInTrashHitZone);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,8 +527,8 @@ public final class ImageEditorView extends FrameLayout {
|
|||
|
||||
public interface DragListener {
|
||||
void onDragStarted(@Nullable EditorElement editorElement);
|
||||
void onDragMoved(@Nullable EditorElement editorElement, @NonNull MotionEvent event);
|
||||
void onDragEnded(@Nullable EditorElement editorElement);
|
||||
void onDragMoved(@Nullable EditorElement editorElement, boolean isInTrashHitZone);
|
||||
void onDragEnded(@Nullable EditorElement editorElement, boolean isInTrashHitZone);
|
||||
}
|
||||
|
||||
public interface TapListener {
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.imageeditor.renderers.CropAreaRenderer;
|
|||
import org.thoughtcrime.securesms.imageeditor.renderers.FillRenderer;
|
||||
import org.thoughtcrime.securesms.imageeditor.renderers.InverseFillRenderer;
|
||||
import org.thoughtcrime.securesms.imageeditor.renderers.OvalGuideRenderer;
|
||||
import org.thoughtcrime.securesms.imageeditor.renderers.TrashRenderer;
|
||||
|
||||
/**
|
||||
* Creates and handles a strict EditorElement Hierarchy.
|
||||
|
@ -71,6 +72,7 @@ final class EditorElementHierarchy {
|
|||
private final EditorElement cropEditorElement;
|
||||
private final EditorElement blackout;
|
||||
private final EditorElement fade;
|
||||
private final EditorElement trash;
|
||||
private final EditorElement thumbs;
|
||||
|
||||
private EditorElementHierarchy(@NonNull EditorElement root) {
|
||||
|
@ -84,6 +86,7 @@ final class EditorElementHierarchy {
|
|||
this.blackout = this.cropEditorElement.getChild(0);
|
||||
this.thumbs = this.cropEditorElement.getChild(1);
|
||||
this.fade = this.cropEditorElement.getChild(2);
|
||||
this.trash = this.cropEditorElement.getChild(3);
|
||||
}
|
||||
|
||||
private enum CropStyle {
|
||||
|
@ -141,6 +144,14 @@ final class EditorElementHierarchy {
|
|||
.persist();
|
||||
cropEditorElement.addElement(fade);
|
||||
|
||||
EditorElement trash = new EditorElement(new TrashRenderer(), EditorModel.Z_TRASH);
|
||||
trash.getFlags()
|
||||
.setSelectable(false)
|
||||
.setEditable(false)
|
||||
.setVisible(false)
|
||||
.persist();
|
||||
cropEditorElement.addElement(trash);
|
||||
|
||||
EditorElement blackout = new EditorElement(new InverseFillRenderer(0xff000000));
|
||||
|
||||
blackout.getFlags()
|
||||
|
@ -212,6 +223,10 @@ final class EditorElementHierarchy {
|
|||
return imageRoot;
|
||||
}
|
||||
|
||||
EditorElement getTrash() {
|
||||
return trash;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main image, null if not yet set.
|
||||
*/
|
||||
|
|
|
@ -41,6 +41,7 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||
public static final int Z_STICKERS = 0;
|
||||
public static final int Z_FADE = 1;
|
||||
public static final int Z_TEXT = 2;
|
||||
public static final int Z_TRASH = 3;
|
||||
|
||||
private static final Runnable NULL_RUNNABLE = () -> {
|
||||
};
|
||||
|
@ -183,6 +184,25 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||
return editorElementHierarchy.getRoot().findElementAt(point.x, point.y, viewMatrix, outInverseModelMatrix);
|
||||
}
|
||||
|
||||
public boolean checkTrashIntersectsPoint(@NonNull PointF point, @NonNull Matrix viewMatrix) {
|
||||
EditorElement trash = editorElementHierarchy.getTrash();
|
||||
if (trash.getFlags().isVisible()) {
|
||||
trash.getFlags()
|
||||
.setSelectable(true)
|
||||
.persist();
|
||||
|
||||
boolean isIntersecting = trash.findElementAt(point.x, point.y, viewMatrix, new Matrix()) != null;
|
||||
|
||||
trash.getFlags()
|
||||
.setSelectable(false)
|
||||
.persist();
|
||||
|
||||
return isIntersecting;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean findElement(@NonNull EditorElement element, @NonNull Matrix viewMatrix, @NonNull Matrix outInverseModelMatrix) {
|
||||
return editorElementHierarchy.getRoot().findElement(element, viewMatrix, outInverseModelMatrix) == element;
|
||||
}
|
||||
|
@ -880,6 +900,10 @@ public final class EditorModel implements Parcelable, RendererContext.Ready {
|
|||
return editorElementHierarchy.getRoot();
|
||||
}
|
||||
|
||||
public EditorElement getTrash() {
|
||||
return editorElementHierarchy.getTrash();
|
||||
}
|
||||
|
||||
public @Nullable EditorElement getMainImage() {
|
||||
return editorElementHierarchy.getMainImage();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
package org.thoughtcrime.securesms.imageeditor.renderers
|
||||
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.RectF
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.imageeditor.Bounds
|
||||
import org.thoughtcrime.securesms.imageeditor.Renderer
|
||||
import org.thoughtcrime.securesms.imageeditor.RendererContext
|
||||
import org.thoughtcrime.securesms.mediasend.v2.MediaAnimations
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
internal class TrashRenderer : InvalidateableRenderer, Renderer, Parcelable {
|
||||
|
||||
private val outlinePaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = Color.WHITE
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = ViewUtil.dpToPx(15) / 10f
|
||||
}
|
||||
|
||||
private val dst = RectF()
|
||||
|
||||
private val diameterSmall = ViewUtil.dpToPx(41)
|
||||
private val diameterLarge = ViewUtil.dpToPx(54)
|
||||
private val trashSize = ViewUtil.dpToPx(24)
|
||||
private val padBottom = ViewUtil.dpToPx(16)
|
||||
|
||||
private var startTime = 0L
|
||||
|
||||
private var isExpanding = false
|
||||
|
||||
private val origin = FloatArray(2)
|
||||
private val x = FloatArray(2)
|
||||
private val a = FloatArray(2)
|
||||
private val b = FloatArray(2)
|
||||
|
||||
constructor() {}
|
||||
|
||||
override fun render(rendererContext: RendererContext) {
|
||||
super.render(rendererContext)
|
||||
|
||||
val frameRenderTime = System.currentTimeMillis()
|
||||
|
||||
val trash: Drawable = requireNotNull(AppCompatResources.getDrawable(rendererContext.context, R.drawable.ic_trash_white_24))
|
||||
trash.setBounds(0, 0, trashSize, trashSize)
|
||||
|
||||
val diameter = getInterpolatedDiameter(frameRenderTime - startTime)
|
||||
|
||||
rendererContext.canvas.save()
|
||||
rendererContext.mapRect(dst, Bounds.FULL_BOUNDS)
|
||||
|
||||
rendererContext.canvasMatrix.setToIdentity()
|
||||
|
||||
rendererContext.canvasMatrix.mapPoints(origin, floatArrayOf(0f, 0f))
|
||||
rendererContext.canvasMatrix.mapPoints(x, floatArrayOf(diameterLarge.toFloat(), 0f))
|
||||
rendererContext.canvasMatrix.mapPoints(a, floatArrayOf(0f, diameterLarge.toFloat() / 2f))
|
||||
rendererContext.canvasMatrix.mapPoints(b, floatArrayOf(0f, padBottom.toFloat()))
|
||||
|
||||
rendererContext.canvas.drawCircle(dst.centerX(), dst.bottom - diameterLarge / 2f - padBottom, diameter / 2f, outlinePaint)
|
||||
rendererContext.canvas.translate(dst.centerX(), dst.bottom - diameterLarge / 2f - padBottom)
|
||||
rendererContext.canvas.translate(- (trashSize / 2f), - (trashSize / 2f))
|
||||
trash.draw(rendererContext.canvas)
|
||||
rendererContext.canvas.restore()
|
||||
|
||||
if (frameRenderTime - DURATION < startTime) {
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun distance(a: FloatArray, b: FloatArray): Float {
|
||||
return sqrt((b[1] - a[1]).toDouble().pow(2.0) + (b[0] - a[0]).toDouble().pow(2.0)).toFloat()
|
||||
}
|
||||
|
||||
private fun getInterpolatedDiameter(timeElapsed: Long): Float {
|
||||
return if (timeElapsed >= DURATION) {
|
||||
if (isExpanding) {
|
||||
diameterLarge.toFloat()
|
||||
} else {
|
||||
diameterSmall.toFloat()
|
||||
}
|
||||
} else {
|
||||
val interpolatedFraction = MediaAnimations.interpolator.getInterpolation(timeElapsed / DURATION.toFloat())
|
||||
if (isExpanding) {
|
||||
interpolateFromFraction(interpolatedFraction)
|
||||
} else {
|
||||
interpolateFromFraction(1 - interpolatedFraction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun interpolateFromFraction(fraction: Float): Float {
|
||||
return diameterSmall + (diameterLarge - diameterSmall) * fraction
|
||||
}
|
||||
|
||||
fun expand() {
|
||||
if (isExpanding) {
|
||||
return
|
||||
}
|
||||
|
||||
isExpanding = true
|
||||
startTime = System.currentTimeMillis()
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun shrink() {
|
||||
if (!isExpanding) {
|
||||
return
|
||||
}
|
||||
|
||||
isExpanding = false
|
||||
startTime = System.currentTimeMillis()
|
||||
invalidate()
|
||||
}
|
||||
|
||||
private constructor(inParcel: Parcel?)
|
||||
|
||||
override fun hitTest(x: Float, y: Float): Boolean {
|
||||
val xDistance = distance(origin, this.x)
|
||||
val isXInRange = -xDistance <= x && x <= xDistance
|
||||
|
||||
if (!isXInRange) {
|
||||
return false
|
||||
}
|
||||
|
||||
val yDistanceStart = dst.bottom - dst.centerY() - distance(origin, a) - distance(origin, b)
|
||||
|
||||
return y >= yDistanceStart
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val DURATION = 150L
|
||||
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<TrashRenderer> = object : Parcelable.Creator<TrashRenderer> {
|
||||
override fun createFromParcel(`in`: Parcel): TrashRenderer {
|
||||
return TrashRenderer(`in`)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<TrashRenderer?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import android.graphics.Point;
|
|||
import android.graphics.RectF;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
@ -131,6 +132,8 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu
|
|||
private ImageEditorHudV2 imageEditorHud;
|
||||
private ImageEditorView imageEditorView;
|
||||
private boolean hasMadeAnEditThisSession;
|
||||
private boolean wasInTrashHitZone;
|
||||
|
||||
|
||||
public static ImageEditorFragment newInstanceForAvatarCapture(@NonNull Uri imageUri) {
|
||||
ImageEditorFragment fragment = newInstance(imageUri);
|
||||
|
@ -407,6 +410,12 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu
|
|||
imageEditorView.getModel().doneCrop();
|
||||
}
|
||||
|
||||
imageEditorView.getModel()
|
||||
.getTrash()
|
||||
.getFlags()
|
||||
.setVisible(mode == ImageEditorHudV2.Mode.DELETE)
|
||||
.persist();
|
||||
|
||||
switch (mode) {
|
||||
case CROP: {
|
||||
imageEditorView.getModel().startCrop();
|
||||
|
@ -838,27 +847,39 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDragMoved(@Nullable EditorElement editorElement, @NonNull MotionEvent event) {
|
||||
public void onDragMoved(@Nullable EditorElement editorElement, boolean isInTrashHitZone) {
|
||||
if (imageEditorHud.getMode() == ImageEditorHudV2.Mode.CROP || editorElement == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
imageEditorHud.onMoved(event);
|
||||
if (imageEditorHud.isInDeleteRect()) {
|
||||
deleteFadeDebouncer.publish(() -> editorElement.animatePartialFadeOut(imageEditorView::invalidate));
|
||||
if (isInTrashHitZone) {
|
||||
deleteFadeDebouncer.publish(() -> {
|
||||
if (!wasInTrashHitZone) {
|
||||
wasInTrashHitZone = true;
|
||||
if (imageEditorHud.isHapticFeedbackEnabled()) {
|
||||
imageEditorHud.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
}
|
||||
}
|
||||
|
||||
editorElement.animatePartialFadeOut(imageEditorView::invalidate);
|
||||
});
|
||||
} else {
|
||||
deleteFadeDebouncer.publish(() -> editorElement.animatePartialFadeIn(imageEditorView::invalidate));
|
||||
deleteFadeDebouncer.publish(() -> {
|
||||
wasInTrashHitZone = false;
|
||||
editorElement.animatePartialFadeIn(imageEditorView::invalidate);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnded(@Nullable EditorElement editorElement) {
|
||||
public void onDragEnded(@Nullable EditorElement editorElement, boolean isInTrashHitZone) {
|
||||
wasInTrashHitZone = false;
|
||||
imageEditorHud.animate().alpha(1f);
|
||||
if (imageEditorHud.getMode() == ImageEditorHudV2.Mode.CROP) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (imageEditorHud.isInDeleteRect()) {
|
||||
if (isInTrashHitZone) {
|
||||
deleteFadeDebouncer.clear();
|
||||
onDelete();
|
||||
setCurrentSelection(null);
|
||||
|
|
|
@ -6,9 +6,7 @@ import android.animation.ObjectAnimator
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
|
@ -28,7 +26,6 @@ import org.thoughtcrime.securesms.scribbles.HSVColorSlider.getColor
|
|||
import org.thoughtcrime.securesms.scribbles.HSVColorSlider.setColor
|
||||
import org.thoughtcrime.securesms.scribbles.HSVColorSlider.setUpForColor
|
||||
import org.thoughtcrime.securesms.util.Debouncer
|
||||
import org.thoughtcrime.securesms.util.ThrottledDebouncer
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
|
||||
|
@ -65,8 +62,6 @@ class ImageEditorHudV2 @JvmOverloads constructor(
|
|||
private val blurToast: View = findViewById(R.id.image_editor_hud_blur_toast)
|
||||
private val blurHelpText: View = findViewById(R.id.image_editor_hud_blur_help_text)
|
||||
private val colorIndicator: ImageView = findViewById(R.id.image_editor_hud_color_indicator)
|
||||
private val delete: FrameLayout = findViewById(R.id.image_editor_hud_delete)
|
||||
private val deleteBackground: View = findViewById(R.id.image_editor_hud_delete_bg)
|
||||
private val bottomGuideline: Guideline = findViewById(R.id.image_editor_bottom_guide)
|
||||
private val brushPreview: BrushWidthPreviewView = findViewById(R.id.image_editor_hud_brush_preview)
|
||||
|
||||
|
@ -78,23 +73,15 @@ class ImageEditorHudV2 @JvmOverloads constructor(
|
|||
private val drawButtonRow: Set<View> = setOf(cancelButton, doneButton, drawButton, textButton, stickerButton, blurButton)
|
||||
private val cropButtonRow: Set<View> = setOf(cancelButton, doneButton, cropRotateButton, cropFlipButton, cropAspectLockButton)
|
||||
|
||||
private val allModeTools: Set<View> = drawTools + blurTools + drawButtonRow + cropButtonRow + delete
|
||||
private val allModeTools: Set<View> = drawTools + blurTools + drawButtonRow + cropButtonRow
|
||||
|
||||
private val viewsToSlide: Set<View> = drawButtonRow + cropButtonRow
|
||||
|
||||
private val toastDebouncer = Debouncer(3000)
|
||||
private var colorIndicatorAlphaAnimator: Animator? = null
|
||||
|
||||
private val deleteDebouncer = ThrottledDebouncer(500)
|
||||
|
||||
private val rect = Rect()
|
||||
|
||||
private var modeAnimatorSet: AnimatorSet? = null
|
||||
private var undoAnimatorSet: AnimatorSet? = null
|
||||
private var deleteSizeAnimatorSet: AnimatorSet? = null
|
||||
|
||||
var isInDeleteRect: Boolean = false
|
||||
private set
|
||||
|
||||
init {
|
||||
initializeViews()
|
||||
|
@ -287,47 +274,6 @@ class ImageEditorHudV2 @JvmOverloads constructor(
|
|||
|
||||
fun getMode(): Mode = currentMode
|
||||
|
||||
fun onMoved(motionEvent: MotionEvent) {
|
||||
delete.getHitRect(rect)
|
||||
if (rect.contains(motionEvent.x.toInt(), motionEvent.y.toInt())) {
|
||||
isInDeleteRect = true
|
||||
deleteDebouncer.publish { scaleDeleteUp() }
|
||||
} else {
|
||||
isInDeleteRect = false
|
||||
deleteDebouncer.publish { scaleDeleteDown() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun scaleDeleteUp() {
|
||||
if (delete.isHapticFeedbackEnabled && deleteBackground.scaleX < 1.365f) {
|
||||
delete.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
|
||||
}
|
||||
|
||||
deleteSizeAnimatorSet?.cancel()
|
||||
deleteSizeAnimatorSet = AnimatorSet().apply {
|
||||
playTogether(
|
||||
ObjectAnimator.ofFloat(deleteBackground, "scaleX", deleteBackground.scaleX, 1.365f),
|
||||
ObjectAnimator.ofFloat(deleteBackground, "scaleY", deleteBackground.scaleY, 1.365f),
|
||||
)
|
||||
duration = ANIMATION_DURATION
|
||||
interpolator = MediaAnimations.interpolator
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun scaleDeleteDown() {
|
||||
deleteSizeAnimatorSet?.cancel()
|
||||
deleteSizeAnimatorSet = AnimatorSet().apply {
|
||||
playTogether(
|
||||
ObjectAnimator.ofFloat(deleteBackground, "scaleX", deleteBackground.scaleX, 1f),
|
||||
ObjectAnimator.ofFloat(deleteBackground, "scaleY", deleteBackground.scaleY, 1f),
|
||||
)
|
||||
duration = ANIMATION_DURATION
|
||||
interpolator = MediaAnimations.interpolator
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
fun setUndoAvailability(undoAvailability: Boolean) {
|
||||
this.undoAvailability = undoAvailability
|
||||
|
||||
|
@ -440,7 +386,6 @@ class ImageEditorHudV2 @JvmOverloads constructor(
|
|||
|
||||
private fun presentModeDelete() {
|
||||
animateModeChange(
|
||||
inSet = setOf(delete),
|
||||
outSet = allModeTools
|
||||
)
|
||||
animateOutUndoTools()
|
||||
|
|
|
@ -374,35 +374,6 @@
|
|||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_end="72dp" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/image_editor_hud_delete"
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="72dp"
|
||||
android:alpha="0"
|
||||
android:contentDescription="@string/ImageEditorHud__delete"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/image_editor_bottom_guide"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_editor_hud_delete_bg"
|
||||
android:layout_width="41dp"
|
||||
android:layout_height="41dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/image_editor_hud_delete_background"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_gravity="center"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerInside"
|
||||
app:srcCompat="@drawable/ic_trash_white_24" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<org.thoughtcrime.securesms.scribbles.BrushWidthPreviewView
|
||||
|
|
Loading…
Add table
Reference in a new issue