mirror of https://github.com/NekoX-Dev/NekoX.git
391 lines
13 KiB
Java
391 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();
|
|
}
|
|
|
|
private PhotoCropViewDelegate delegate;
|
|
|
|
private CropView cropView;
|
|
private 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) {
|
|
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);
|
|
if (delegate != null) {
|
|
delegate.onChange(false);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onEnd(float angle) {
|
|
cropView.onRotationEnded();
|
|
}
|
|
|
|
@Override
|
|
public void aspectRatioPressed() {
|
|
cropView.showAspectRatioDialog();
|
|
}
|
|
|
|
@Override
|
|
public boolean rotate90Pressed() {
|
|
return rotate();
|
|
}
|
|
|
|
@Override
|
|
public boolean mirror() {
|
|
return PhotoCropView.this.mirror();
|
|
}
|
|
});
|
|
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() {
|
|
if (wheelView != null) {
|
|
wheelView.reset(false);
|
|
}
|
|
return cropView.rotate90Degrees();
|
|
}
|
|
|
|
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() {
|
|
wheelView.reset(true);
|
|
cropView.reset();
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|