NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoCropView.java

406 lines
13 KiB
Java

/*
* This is the source code of Telegram for Android v. 5.x.x
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.ui.Components;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.Property;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ImageReceiver;
import org.telegram.messenger.MediaController;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.BubbleActivity;
import org.telegram.ui.Components.Crop.CropRotationWheel;
import org.telegram.ui.Components.Crop.CropTransform;
import org.telegram.ui.Components.Crop.CropView;
public class PhotoCropView extends FrameLayout {
public interface PhotoCropViewDelegate {
void onChange(boolean reset);
void onUpdate();
void onTapUp();
int getVideoThumbX();
void onVideoThumbClick();
boolean rotate();
boolean mirror();
}
private PhotoCropViewDelegate delegate;
public boolean isReset = true;
public CropView cropView;
public CropRotationWheel wheelView;
private boolean inBubbleMode;
private ImageReceiver thumbImageView;
private boolean thumbImageVisible;
private boolean thumbImageVisibleOverride = true;
private float thumbImageVisibleProgress;
private float thumbAnimationProgress = 1.0f;
private AnimatorSet thumbAnimation;
private AnimatorSet thumbOverrideAnimation;
private float flashAlpha = 0.0f;
private Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Theme.ResourcesProvider resourcesProvider;
public final Property<PhotoCropView, Float> ANIMATION_VALUE = new AnimationProperties.FloatProperty<PhotoCropView>("thumbAnimationProgress") {
@Override
public void setValue(PhotoCropView object, float value) {
thumbAnimationProgress = value;
object.invalidate();
}
@Override
public Float get(PhotoCropView object) {
return thumbAnimationProgress;
}
};
public final Property<PhotoCropView, Float> PROGRESS_VALUE = new AnimationProperties.FloatProperty<PhotoCropView>("thumbImageVisibleProgress") {
@Override
public void setValue(PhotoCropView object, float value) {
thumbImageVisibleProgress = value;
object.invalidate();
}
@Override
public Float get(PhotoCropView object) {
return thumbImageVisibleProgress;
}
};
public PhotoCropView(Context context, Theme.ResourcesProvider resourcesProvider) {
super(context);
this.resourcesProvider = resourcesProvider;
inBubbleMode = context instanceof BubbleActivity;
cropView = new CropView(context);
cropView.setListener(new CropView.CropViewListener() {
@Override
public void onChange(boolean reset) {
isReset = reset;
if (delegate != null) {
delegate.onChange(reset);
}
}
@Override
public void onUpdate() {
if (delegate != null) {
delegate.onUpdate();
}
}
@Override
public void onAspectLock(boolean enabled) {
wheelView.setAspectLock(enabled);
}
@Override
public void onTapUp() {
if (delegate != null) {
delegate.onTapUp();
}
}
});
cropView.setBottomPadding(AndroidUtilities.dp(64));
addView(cropView);
thumbImageView = new ImageReceiver(this);
wheelView = new CropRotationWheel(context);
wheelView.setListener(new CropRotationWheel.RotationWheelListener() {
@Override
public void onStart() {
cropView.onRotationBegan();
}
@Override
public void onChange(float angle) {
cropView.setRotation(angle);
isReset = false;
if (delegate != null) {
delegate.onChange(false);
}
}
@Override
public void onEnd(float angle) {
cropView.onRotationEnded();
}
@Override
public void aspectRatioPressed() {
cropView.showAspectRatioDialog();
}
@Override
public boolean rotate90Pressed() {
if (delegate != null) {
return delegate.rotate();
}
return false;
}
@Override
public boolean mirror() {
if (delegate != null) {
return delegate.mirror();
}
return false;
}
});
addView(wheelView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER | Gravity.BOTTOM, 0, 0, 0, 0));
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (thumbImageVisibleOverride && thumbImageVisible && thumbImageView.isInsideImage(event.getX(), event.getY())) {
if (event.getAction() == MotionEvent.ACTION_UP) {
delegate.onVideoThumbClick();
}
return true;
}
return super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (thumbImageVisibleOverride && thumbImageVisible && thumbImageView.isInsideImage(event.getX(), event.getY())) {
if (event.getAction() == MotionEvent.ACTION_UP) {
delegate.onVideoThumbClick();
}
return true;
}
return super.onTouchEvent(event);
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean result = super.drawChild(canvas, child, drawingTime);
if (thumbImageVisible && child == cropView) {
RectF rect = cropView.getActualRect();
int targetSize = AndroidUtilities.dp(32);
int targetX = delegate.getVideoThumbX() - targetSize / 2 + AndroidUtilities.dp(2);
int targetY = getMeasuredHeight() - AndroidUtilities.dp(156);
float x = rect.left + (targetX - rect.left) * thumbAnimationProgress;
float y = rect.top + (targetY - rect.top) * thumbAnimationProgress;
float size = rect.width() + (targetSize - rect.width()) * thumbAnimationProgress;
thumbImageView.setRoundRadius((int) (size / 2));
thumbImageView.setImageCoords(x, y, size, size);
thumbImageView.setAlpha(thumbImageVisibleProgress);
thumbImageView.draw(canvas);
if (flashAlpha > 0.0f) {
circlePaint.setColor(0xffffffff);
circlePaint.setAlpha((int) (flashAlpha * 255));
canvas.drawCircle(rect.centerX(), rect.centerY(), rect.width() / 2, circlePaint);
}
circlePaint.setColor(getThemedColor(Theme.key_dialogFloatingButton));
circlePaint.setAlpha(Math.min(255, (int) (255 * thumbAnimationProgress * thumbImageVisibleProgress)));
canvas.drawCircle(targetX + targetSize / 2, targetY + targetSize + AndroidUtilities.dp(8), AndroidUtilities.dp(3), circlePaint);
}
return result;
}
public boolean rotate(float diff) {
if (wheelView != null) {
wheelView.reset(false);
}
return cropView.rotate(diff);
}
public boolean mirror() {
return cropView.mirror();
}
public void setBitmap(Bitmap bitmap, int rotation, boolean freeform, boolean update, PaintingOverlay paintingOverlay, CropTransform cropTransform, VideoEditTextureView videoView, MediaController.CropState state) {
requestLayout();
thumbImageVisible = false;
thumbImageView.setImageBitmap((Drawable) null);
cropView.setBitmap(bitmap, rotation, freeform, update, paintingOverlay, cropTransform, videoView, state);
wheelView.setFreeform(freeform);
wheelView.reset(true);
if (state != null) {
wheelView.setRotation(state.cropRotate, false);
wheelView.setRotated(state.transformRotation != 0);
wheelView.setMirrored(state.mirrored);
} else {
wheelView.setRotated(false);
wheelView.setMirrored(false);
}
wheelView.setVisibility(freeform ? VISIBLE : INVISIBLE);
}
public void setVideoThumbFlashAlpha(float alpha) {
flashAlpha = alpha;
invalidate();
}
public Bitmap getVideoThumb() {
return thumbImageVisible && thumbImageVisibleOverride ? thumbImageView.getBitmap() : null;
}
public void setVideoThumb(Bitmap bitmap, int orientation) {
thumbImageVisible = bitmap != null;
thumbImageView.setImageBitmap(bitmap);
thumbImageView.setOrientation(orientation, false);
if (thumbAnimation != null) {
thumbAnimation.cancel();
}
if (thumbOverrideAnimation != null) {
thumbOverrideAnimation.cancel();
}
thumbImageVisibleOverride = true;
thumbImageVisibleProgress = 1.0f;
thumbAnimation = new AnimatorSet();
thumbAnimation.playTogether(ObjectAnimator.ofFloat(this, ANIMATION_VALUE, 0.0f, 1.0f));
thumbAnimation.setDuration(250);
thumbAnimation.setInterpolator(new OvershootInterpolator(1.01f));
thumbAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
thumbAnimation = null;
}
});
thumbAnimation.start();
}
public void cancelThumbAnimation() {
if (thumbAnimation != null) {
thumbAnimation.cancel();
thumbAnimation = null;
thumbImageVisible = false;
}
}
public void setVideoThumbVisible(boolean visible) {
if (thumbImageVisibleOverride == visible) {
return;
}
thumbImageVisibleOverride = visible;
if (thumbOverrideAnimation != null) {
thumbOverrideAnimation.cancel();
}
thumbOverrideAnimation = new AnimatorSet();
thumbOverrideAnimation.playTogether(ObjectAnimator.ofFloat(this, PROGRESS_VALUE, visible ? 1.0f : 0.0f));
thumbOverrideAnimation.setDuration(180);
thumbOverrideAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
thumbOverrideAnimation = null;
}
});
thumbOverrideAnimation.start();
}
public boolean isReady() {
return cropView.isReady();
}
public void reset() {
reset(false);
}
public void reset(boolean force) {
wheelView.reset(true);
cropView.reset(force);
}
public void onAppear() {
cropView.willShow();
}
public void setAspectRatio(float ratio) {
cropView.setAspectRatio(ratio);
}
public void setFreeform(boolean freeform) {
cropView.setFreeform(freeform);
}
public void onAppeared() {
cropView.show();
}
public void onDisappear() {
cropView.hide();
}
public void onShow() {
cropView.onShow();
}
public void onHide() {
cropView.onHide();
}
public float getRectX() {
return cropView.getCropLeft() - AndroidUtilities.dp(14);
}
public float getRectY() {
return cropView.getCropTop() - AndroidUtilities.dp(14) - (Build.VERSION.SDK_INT >= 21 && !inBubbleMode ? AndroidUtilities.statusBarHeight : 0);
}
public float getRectSizeX() {
return cropView.getCropWidth();
}
public float getRectSizeY() {
return cropView.getCropHeight();
}
public void makeCrop(MediaController.MediaEditState editState) {
cropView.makeCrop(editState);
}
public void setDelegate(PhotoCropViewDelegate photoCropViewDelegate) {
delegate = photoCropViewDelegate;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
cropView.updateLayout();
}
@Override
public void invalidate() {
super.invalidate();
cropView.invalidate();
}
private int getThemedColor(String key) {
Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null;
return color != null ? color : Theme.getColor(key);
}
}