464 lines
18 KiB
Java
464 lines
18 KiB
Java
|
/*
|
||
|
* This is the source code of Telegram for Android v. 1.4.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-2014.
|
||
|
*/
|
||
|
|
||
|
package org.telegram.ui;
|
||
|
|
||
|
import android.animation.Animator;
|
||
|
import android.animation.AnimatorListenerAdapter;
|
||
|
import android.animation.AnimatorSet;
|
||
|
import android.animation.ObjectAnimator;
|
||
|
import android.app.Activity;
|
||
|
import android.content.Context;
|
||
|
import android.graphics.Bitmap;
|
||
|
import android.graphics.Canvas;
|
||
|
import android.graphics.Paint;
|
||
|
import android.graphics.PixelFormat;
|
||
|
import android.graphics.Rect;
|
||
|
import android.graphics.drawable.ColorDrawable;
|
||
|
import android.view.Gravity;
|
||
|
import android.view.MotionEvent;
|
||
|
import android.view.View;
|
||
|
import android.view.ViewGroup;
|
||
|
import android.view.ViewTreeObserver;
|
||
|
import android.view.WindowManager;
|
||
|
import android.widget.FrameLayout;
|
||
|
|
||
|
import org.telegram.messenger.R;
|
||
|
import org.telegram.messenger.Utilities;
|
||
|
import org.telegram.ui.Views.ActionBar.ActionBar;
|
||
|
import org.telegram.ui.Views.ActionBar.ActionBarLayer;
|
||
|
import org.telegram.ui.Views.ActionBar.ActionBarMenu;
|
||
|
import org.telegram.ui.Views.ImageReceiver;
|
||
|
|
||
|
public class PhotoViewer {
|
||
|
private FrameLayout containerView;
|
||
|
private ClippingImageView animatingImageView;
|
||
|
private ColorDrawable backgroundDrawable = new ColorDrawable(0xff000000);
|
||
|
private View parentView;
|
||
|
private int imageX, imageY;
|
||
|
private ImageReceiver currentImageReceiver;
|
||
|
private boolean animationInProgress = false;
|
||
|
private ActionBar actionBar;
|
||
|
private ActionBarLayer actionBarLayer;
|
||
|
private Activity parentActivity;
|
||
|
private WindowManager.LayoutParams windowLayoutParams;
|
||
|
private boolean isVisible;
|
||
|
private boolean isActionBarVisible = true;
|
||
|
|
||
|
public static class FrameLayoutTest extends FrameLayout {
|
||
|
public FrameLayoutTest(Context context) {
|
||
|
super(context);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean onTouchEvent(MotionEvent event) {
|
||
|
return getInstance().onTouchEvent(event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class ClippingImageView extends View {
|
||
|
private int clipBottom;
|
||
|
private int clipLeft;
|
||
|
private int clipRight;
|
||
|
private int clipTop;
|
||
|
private Rect drawRect;
|
||
|
private Paint paint;
|
||
|
private Bitmap bmp;
|
||
|
public onDrawListener drawListener;
|
||
|
|
||
|
public static interface onDrawListener {
|
||
|
public abstract void onDraw();
|
||
|
}
|
||
|
|
||
|
public ClippingImageView(Context paramContext) {
|
||
|
super(paramContext);
|
||
|
paint = new Paint();
|
||
|
paint.setFilterBitmap(true);
|
||
|
drawRect = new Rect();
|
||
|
}
|
||
|
|
||
|
public int getClipBottom() {
|
||
|
return clipBottom;
|
||
|
}
|
||
|
|
||
|
public int getClipHorizontal() {
|
||
|
return clipRight;
|
||
|
}
|
||
|
|
||
|
public int getClipLeft() {
|
||
|
return clipLeft;
|
||
|
}
|
||
|
|
||
|
public int getClipRight() {
|
||
|
return clipRight;
|
||
|
}
|
||
|
|
||
|
public int getClipTop() {
|
||
|
return clipTop;
|
||
|
}
|
||
|
|
||
|
public void onDraw(Canvas canvas) {
|
||
|
if (drawListener != null) {
|
||
|
drawListener.onDraw();
|
||
|
}
|
||
|
if (bmp != null) {
|
||
|
canvas.save();
|
||
|
canvas.clipRect(clipLeft / getScaleY(), clipTop / getScaleY(), getWidth() - clipRight / getScaleY(), getHeight() - clipBottom / getScaleY());
|
||
|
drawRect.set(0, 0, getWidth(), getHeight());
|
||
|
canvas.drawBitmap(this.bmp, null, drawRect, this.paint);
|
||
|
canvas.restore();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void setClipBottom(int value) {
|
||
|
clipBottom = value;
|
||
|
invalidate();
|
||
|
}
|
||
|
|
||
|
public void setClipHorizontal(int value) {
|
||
|
clipRight = value;
|
||
|
clipLeft = value;
|
||
|
invalidate();
|
||
|
}
|
||
|
|
||
|
public void setClipLeft(int value) {
|
||
|
clipLeft = value;
|
||
|
invalidate();
|
||
|
}
|
||
|
|
||
|
public void setClipRight(int value) {
|
||
|
clipRight = value;
|
||
|
invalidate();
|
||
|
}
|
||
|
|
||
|
public void setClipTop(int value) {
|
||
|
clipTop = value;
|
||
|
invalidate();
|
||
|
}
|
||
|
|
||
|
public void setClipVertical(int value) {
|
||
|
clipBottom = value;
|
||
|
clipTop = value;
|
||
|
invalidate();
|
||
|
}
|
||
|
|
||
|
public void setImageBitmap(Bitmap bitmap) {
|
||
|
bmp = bitmap;
|
||
|
invalidate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static volatile PhotoViewer Instance = null;
|
||
|
public static PhotoViewer getInstance() {
|
||
|
PhotoViewer localInstance = Instance;
|
||
|
if (localInstance == null) {
|
||
|
synchronized (PhotoViewer.class) {
|
||
|
localInstance = Instance;
|
||
|
if (localInstance == null) {
|
||
|
Instance = localInstance = new PhotoViewer();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return localInstance;
|
||
|
}
|
||
|
|
||
|
public void setParentActivity(Activity activity) {
|
||
|
parentActivity = activity;
|
||
|
|
||
|
containerView = new FrameLayoutTest(activity);
|
||
|
containerView.setFocusable(false);
|
||
|
containerView.setBackground(backgroundDrawable);
|
||
|
|
||
|
windowLayoutParams = new WindowManager.LayoutParams();
|
||
|
windowLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
|
||
|
windowLayoutParams.format = PixelFormat.TRANSLUCENT;
|
||
|
windowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
|
||
|
windowLayoutParams.gravity = Gravity.TOP;
|
||
|
windowLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||
|
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||
|
|
||
|
animatingImageView = new ClippingImageView(containerView.getContext());
|
||
|
containerView.addView(animatingImageView);
|
||
|
|
||
|
actionBar = new ActionBar(activity);
|
||
|
containerView.addView(actionBar);
|
||
|
actionBar.setBackgroundColor(0xdd000000);
|
||
|
actionBar.setItemsBackground(R.drawable.bar_selector_white);
|
||
|
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)actionBar.getLayoutParams();
|
||
|
layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT;
|
||
|
actionBar.setLayoutParams(layoutParams);
|
||
|
actionBarLayer = actionBar.createLayer();
|
||
|
actionBarLayer.setDisplayHomeAsUpEnabled(true);
|
||
|
actionBarLayer.setTitle("Photo");
|
||
|
actionBar.setCurrentActionBarLayer(actionBarLayer);
|
||
|
|
||
|
actionBarLayer.setActionBarMenuOnItemClick(new ActionBarLayer.ActionBarMenuOnItemClick() {
|
||
|
@Override
|
||
|
public void onItemClick(int id) {
|
||
|
if (id == -1) {
|
||
|
closePhoto();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
ActionBarMenu menu = actionBarLayer.createMenu();
|
||
|
menu.addItem(0, R.drawable.ic_ab_other_white);
|
||
|
}
|
||
|
|
||
|
public void openPhoto(final ImageReceiver imageReceiver, final int x, final int y, final View parent) {
|
||
|
if (parentActivity == null || isVisible) {
|
||
|
return;
|
||
|
}
|
||
|
WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE);
|
||
|
wm.addView(containerView, windowLayoutParams);
|
||
|
|
||
|
if(android.os.Build.VERSION.SDK_INT >= 11) {
|
||
|
if (animationInProgress) {
|
||
|
return;
|
||
|
}
|
||
|
isVisible = true;
|
||
|
animationInProgress = true;
|
||
|
toggleActionBar(true, false);
|
||
|
parentView = parent;
|
||
|
imageX = x;
|
||
|
imageY = y;
|
||
|
|
||
|
currentImageReceiver = imageReceiver;
|
||
|
animatingImageView.setVisibility(View.VISIBLE);
|
||
|
containerView.invalidate();
|
||
|
animatingImageView.invalidate();
|
||
|
animatingImageView.setImageBitmap(imageReceiver.getBitmap());
|
||
|
|
||
|
containerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||
|
@Override
|
||
|
public boolean onPreDraw() {
|
||
|
containerView.getViewTreeObserver().removeOnPreDrawListener(this);
|
||
|
animatingImageView.drawListener = new ClippingImageView.onDrawListener() {
|
||
|
@Override
|
||
|
public void onDraw() {
|
||
|
animatingImageView.drawListener = null;
|
||
|
animatingImageView.post(new Runnable() {
|
||
|
@Override
|
||
|
public void run() {
|
||
|
imageReceiver.setVisible(false);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
animatingImageView.setPivotX(0);
|
||
|
animatingImageView.setPivotY(0);
|
||
|
animatingImageView.setScaleX(1);
|
||
|
animatingImageView.setScaleY(1);
|
||
|
animatingImageView.setTranslationX(x + imageReceiver.drawRegion.left);
|
||
|
animatingImageView.setTranslationY(y + imageReceiver.drawRegion.top);
|
||
|
ViewGroup.LayoutParams layoutParams = animatingImageView.getLayoutParams();
|
||
|
layoutParams.width = imageReceiver.drawRegion.right - imageReceiver.drawRegion.left;
|
||
|
layoutParams.height = imageReceiver.drawRegion.bottom - imageReceiver.drawRegion.top;
|
||
|
animatingImageView.setLayoutParams(layoutParams);
|
||
|
|
||
|
|
||
|
float scaleX = (float)Utilities.displaySize.x / layoutParams.width;
|
||
|
float scaleY = (float)(Utilities.displaySize.y - Utilities.statusBarHeight) / layoutParams.height;
|
||
|
float scale = scaleX > scaleY ? scaleY : scaleX;
|
||
|
float width = layoutParams.width * scale;
|
||
|
float height = layoutParams.height * scale;
|
||
|
float xPos = (Utilities.displaySize.x - width) / 2.0f;
|
||
|
float yPos = (Utilities.displaySize.y - Utilities.statusBarHeight - height) / 2.0f;
|
||
|
int clipHorizontal = Math.abs(imageReceiver.drawRegion.left - imageReceiver.imageX);
|
||
|
|
||
|
int coords2[] = new int[2];
|
||
|
parent.getLocationInWindow(coords2);
|
||
|
int clipTop = coords2[1] - Utilities.statusBarHeight - (y + imageReceiver.drawRegion.top);
|
||
|
if (clipTop < 0) {
|
||
|
clipTop = 0;
|
||
|
}
|
||
|
int clipBottom = (y + imageReceiver.drawRegion.top + layoutParams.height) - (coords2[1] + parent.getHeight() - Utilities.statusBarHeight);
|
||
|
if (clipBottom < 0) {
|
||
|
clipBottom = 0;
|
||
|
}
|
||
|
|
||
|
AnimatorSet animatorSet = new AnimatorSet();
|
||
|
animatorSet.playTogether(
|
||
|
ObjectAnimator.ofFloat(animatingImageView, "scaleX", scale),
|
||
|
ObjectAnimator.ofFloat(animatingImageView, "scaleY", scale),
|
||
|
ObjectAnimator.ofFloat(animatingImageView, "translationX", xPos),
|
||
|
ObjectAnimator.ofFloat(animatingImageView, "translationY", yPos),
|
||
|
ObjectAnimator.ofInt(backgroundDrawable, "alpha", 0, 255),
|
||
|
ObjectAnimator.ofInt(animatingImageView, "clipHorizontal", clipHorizontal, 0),
|
||
|
ObjectAnimator.ofInt(animatingImageView, "clipTop", clipTop, 0),
|
||
|
ObjectAnimator.ofInt(animatingImageView, "clipBottom", clipBottom, 0),
|
||
|
ObjectAnimator.ofFloat(actionBar, "alpha", 0.0f, 1.0f)
|
||
|
);
|
||
|
|
||
|
animatorSet.setDuration(250);
|
||
|
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||
|
@Override
|
||
|
public void onAnimationEnd(Animator animation) {
|
||
|
animationInProgress = false;
|
||
|
}
|
||
|
});
|
||
|
animatorSet.start();
|
||
|
return true;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void closePhoto() {
|
||
|
if (parentActivity == null || !isVisible) {
|
||
|
return;
|
||
|
}
|
||
|
if(android.os.Build.VERSION.SDK_INT >= 11) {
|
||
|
if (animationInProgress) {
|
||
|
return;
|
||
|
}
|
||
|
isVisible = false;
|
||
|
animationInProgress = true;
|
||
|
isActionBarVisible = false;
|
||
|
animatingImageView.setVisibility(View.VISIBLE);
|
||
|
|
||
|
int clipHorizontal = Math.abs(currentImageReceiver.drawRegion.left - currentImageReceiver.imageX);
|
||
|
|
||
|
int coords2[] = new int[2];
|
||
|
parentView.getLocationInWindow(coords2);
|
||
|
int clipTop = coords2[1] - Utilities.statusBarHeight - (imageY + currentImageReceiver.drawRegion.top);
|
||
|
if (clipTop < 0) {
|
||
|
clipTop = 0;
|
||
|
}
|
||
|
int clipBottom = (imageY + currentImageReceiver.drawRegion.top + (currentImageReceiver.drawRegion.bottom - currentImageReceiver.drawRegion.top)) - (coords2[1] + parentView.getHeight() - Utilities.statusBarHeight);
|
||
|
if (clipBottom < 0) {
|
||
|
clipBottom = 0;
|
||
|
}
|
||
|
|
||
|
AnimatorSet animatorSet = new AnimatorSet();
|
||
|
animatorSet.playTogether(
|
||
|
ObjectAnimator.ofFloat(animatingImageView, "scaleX", 1),
|
||
|
ObjectAnimator.ofFloat(animatingImageView, "scaleY", 1),
|
||
|
ObjectAnimator.ofFloat(animatingImageView, "translationX", imageX + currentImageReceiver.drawRegion.left),
|
||
|
ObjectAnimator.ofFloat(animatingImageView, "translationY", imageY + currentImageReceiver.drawRegion.top),
|
||
|
ObjectAnimator.ofInt(backgroundDrawable, "alpha", 0),
|
||
|
ObjectAnimator.ofInt(animatingImageView, "clipHorizontal", clipHorizontal),
|
||
|
ObjectAnimator.ofInt(animatingImageView, "clipTop", clipTop),
|
||
|
ObjectAnimator.ofInt(animatingImageView, "clipBottom", clipBottom),
|
||
|
ObjectAnimator.ofFloat(actionBar, "alpha", 0.0f)
|
||
|
);
|
||
|
|
||
|
animatorSet.setDuration(250);
|
||
|
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||
|
@Override
|
||
|
public void onAnimationEnd(Animator animation) {
|
||
|
containerView.post(new Runnable() {
|
||
|
@Override
|
||
|
public void run() {
|
||
|
WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE);
|
||
|
wm.removeView(containerView);
|
||
|
}
|
||
|
});
|
||
|
animationInProgress = false;
|
||
|
currentImageReceiver.setVisible(true);
|
||
|
}
|
||
|
});
|
||
|
animatorSet.start();
|
||
|
} else {
|
||
|
WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE);
|
||
|
wm.removeView(containerView);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public boolean isVisible() {
|
||
|
return isVisible;
|
||
|
}
|
||
|
|
||
|
private boolean maybeStartDragDown = false;
|
||
|
private boolean draggingDown = false;
|
||
|
private int startDraggingPointerIndex = -1;
|
||
|
private float dragY;
|
||
|
private float startDragOriginY = 0;
|
||
|
|
||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||
|
if (animationInProgress) {
|
||
|
return false;
|
||
|
}
|
||
|
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||
|
if (!maybeStartDragDown) {
|
||
|
maybeStartDragDown = true;
|
||
|
dragY = ev.getY();
|
||
|
}
|
||
|
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
|
||
|
if (!draggingDown && maybeStartDragDown) {
|
||
|
if (Math.abs(ev.getY() - dragY) >= Utilities.dp(10)) {
|
||
|
draggingDown = true;
|
||
|
maybeStartDragDown = false;
|
||
|
dragY = ev.getY();
|
||
|
startDragOriginY = animatingImageView.getTranslationY();
|
||
|
if (isActionBarVisible) {
|
||
|
toggleActionBar(false, true);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
} else if (draggingDown) {
|
||
|
float diff = ev.getY() - dragY;
|
||
|
float maxValue = Utilities.displaySize.y / 4.0f;
|
||
|
backgroundDrawable.setAlpha((int)Math.max(127, 255 * (1.0f - (Math.min(Math.abs(diff), maxValue) / maxValue))));
|
||
|
animatingImageView.setTranslationY(startDragOriginY + diff);
|
||
|
}
|
||
|
} else if (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP) {
|
||
|
if (draggingDown) {
|
||
|
if (Math.abs(dragY - ev.getY()) > Utilities.displaySize.y / 6.0f) {
|
||
|
closePhoto();
|
||
|
} else {
|
||
|
AnimatorSet animatorSet = new AnimatorSet();
|
||
|
animatorSet.playTogether(
|
||
|
ObjectAnimator.ofFloat(animatingImageView, "translationY", startDragOriginY),
|
||
|
ObjectAnimator.ofInt(backgroundDrawable, "alpha", 255)
|
||
|
);
|
||
|
|
||
|
animatorSet.setDuration(250);
|
||
|
animatorSet.start();
|
||
|
}
|
||
|
draggingDown = false;
|
||
|
} else {
|
||
|
toggleActionBar(!isActionBarVisible, true);
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private void toggleActionBar(boolean show, boolean animated) {
|
||
|
if (show) {
|
||
|
actionBar.setVisibility(View.VISIBLE);
|
||
|
}
|
||
|
isActionBarVisible = show;
|
||
|
actionBar.setEnabled(show);
|
||
|
actionBarLayer.setEnabled(show);
|
||
|
if (animated) {
|
||
|
AnimatorSet animatorSet = new AnimatorSet();
|
||
|
animatorSet.playTogether(
|
||
|
ObjectAnimator.ofFloat(actionBar, "alpha", show ? 1.0f : 0.0f)
|
||
|
);
|
||
|
if (!show) {
|
||
|
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||
|
@Override
|
||
|
public void onAnimationEnd(Animator animation) {
|
||
|
actionBar.setVisibility(View.GONE);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
animatorSet.setDuration(250);
|
||
|
animatorSet.start();
|
||
|
} else {
|
||
|
actionBar.setAlpha(show ? 1.0f : 0.0f);
|
||
|
if (!show) {
|
||
|
actionBar.setVisibility(View.GONE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|