Java tutorial
/* * This is the source code of Telegram for Android v. 3.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-2016. */ package org.telegram.ui; import android.Manifest; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v4.content.FileProvider; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.TypedValue; import android.view.ActionMode; import android.view.ContextThemeWrapper; import android.view.GestureDetector; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; import android.view.TextureView; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.Scroller; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildConfig; import org.telegram.messenger.Emoji; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.UserObject; import org.telegram.messenger.exoplayer.AspectRatioFrameLayout; import org.telegram.messenger.exoplayer.ExoPlayer; import org.telegram.messenger.exoplayer.util.PlayerControl; import org.telegram.messenger.query.SharedMediaQuery; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.UserConfig; import org.telegram.messenger.MessageObject; import org.telegram.messenger.Utilities; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.MentionsAdapter; import org.telegram.messenger.AnimatorListenerAdapterProxy; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.CheckBox; import org.telegram.ui.Components.ClippingImageView; import org.telegram.messenger.ImageReceiver; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.PhotoCropView; import org.telegram.ui.Components.PhotoFilterView; import org.telegram.ui.Components.PhotoPaintView; import org.telegram.ui.Components.PhotoViewerCaptionEnterView; import org.telegram.ui.Components.PickerBottomLayoutViewer; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SeekBar; import org.telegram.ui.Components.SizeNotifierFrameLayoutPhoto; import org.telegram.ui.Components.StickersAlert; import org.telegram.ui.Components.VideoPlayer; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Locale; @SuppressWarnings("unchecked") public class PhotoViewer implements NotificationCenter.NotificationCenterDelegate, GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { private int classGuid; private PhotoViewerProvider placeProvider; private boolean isVisible; private boolean muteVideo; private Activity parentActivity; private Context actvityContext; private ActionBar actionBar; private boolean isActionBarVisible = true; private static Drawable[] progressDrawables; private WindowManager.LayoutParams windowLayoutParams; private FrameLayoutDrawer containerView; private FrameLayout windowView; private ClippingImageView animatingImageView; private FrameLayout bottomLayout; private TextView nameTextView; private TextView dateTextView; private ActionBarMenuItem menuItem; private ActionBarMenuItem muteItem; private ActionBarMenuItem masksItem; private boolean muteItemAvailable; private ImageView shareButton; private BackgroundDrawable backgroundDrawable = new BackgroundDrawable(0xff000000); private Paint blackPaint = new Paint(); private CheckBox checkImageView; private PickerBottomLayoutViewer pickerView; private PickerBottomLayoutViewer editorDoneLayout; private RadialProgressView radialProgressViews[] = new RadialProgressView[3]; private ImageView paintItem; private ImageView cropItem; private ImageView tuneItem; private ActionBarMenuItem captionDoneItem; private AnimatorSet currentActionBarAnimation; private PhotoCropView photoCropView; private PhotoFilterView photoFilterView; private PhotoPaintView photoPaintView; private AlertDialog visibleDialog; private TextView captionTextView; private TextView captionTextViewOld; private TextView captionTextViewNew; private PhotoViewerCaptionEnterView captionEditText; private boolean canShowBottom = true; private int sendPhotoType; private boolean needCaptionLayout; private AnimatedFileDrawable currentAnimation; private boolean allowShare; private Object lastInsets; private AspectRatioFrameLayout aspectRatioFrameLayout; private TextureView videoTextureView; private VideoPlayer videoPlayer; private FrameLayout videoPlayerControlFrameLayout; private ImageView videoPlayButton; private TextView videoPlayerTime; private SeekBar videoPlayerSeekbar; private boolean playerNeedsPrepare; private boolean textureUploaded; private boolean videoCrossfadeStarted; private float videoCrossfadeAlpha; private long videoCrossfadeAlphaLastTime; private boolean isPlaying; private Runnable updateProgressRunnable = new Runnable() { @Override public void run() { if (videoPlayer != null && videoPlayerSeekbar != null) { if (!videoPlayerSeekbar.isDragging()) { PlayerControl playerControl = videoPlayer.getPlayerControl(); float progress = playerControl.getCurrentPosition() / (float) playerControl.getDuration(); videoPlayerSeekbar.setProgress(progress); videoPlayerControlFrameLayout.invalidate(); updateVideoPlayerTime(); } } if (isPlaying) { AndroidUtilities.runOnUIThread(updateProgressRunnable, 100); } } }; private float animationValues[][] = new float[2][8]; private ChatActivity parentChatActivity; private MentionsAdapter mentionsAdapter; private RecyclerListView mentionListView; private LinearLayoutManager mentionLayoutManager; private AnimatorSet mentionListAnimation; private boolean allowMentions; private int animationInProgress = 0; private long transitionAnimationStartTime = 0; private Runnable animationEndRunnable = null; private PlaceProviderObject showAfterAnimation; private PlaceProviderObject hideAfterAnimation; private boolean disableShowCheck = false; private String lastTitle; private int currentEditMode; private ImageReceiver leftImage = new ImageReceiver(); private ImageReceiver centerImage = new ImageReceiver(); private ImageReceiver rightImage = new ImageReceiver(); private int currentIndex; private MessageObject currentMessageObject; private TLRPC.BotInlineResult currentBotInlineResult; private TLRPC.FileLocation currentFileLocation; private String currentFileNames[] = new String[3]; private PlaceProviderObject currentPlaceObject; private String currentPathObject; private Bitmap currentThumb = null; private int avatarsDialogId; private long currentDialogId; private long mergeDialogId; private int totalImagesCount; private int totalImagesCountMerge; private boolean isFirstLoading; private boolean needSearchImageInArr; private boolean loadingMoreImages; private boolean endReached[] = new boolean[] { false, true }; private boolean opennedFromMedia; private boolean attachedToWindow; private boolean wasLayout; private boolean dontResetZoomOnFirstLayout; private boolean draggingDown = false; private float dragY; private float translationX; private float translationY; private float scale = 1; private float animateToX; private float animateToY; private float animateToScale; private float animationValue; private int currentRotation; private long animationStartTime; private AnimatorSet imageMoveAnimation; private AnimatorSet changeModeAnimation; private GestureDetector gestureDetector; private DecelerateInterpolator interpolator = new DecelerateInterpolator(1.5f); private float pinchStartDistance; private float pinchStartScale = 1; private float pinchCenterX; private float pinchCenterY; private float pinchStartX; private float pinchStartY; private float moveStartX; private float moveStartY; private float minX; private float maxX; private float minY; private float maxY; private boolean canZoom = true; private boolean changingPage = false; private boolean zooming = false; private boolean moving = false; private boolean doubleTap = false; private boolean invalidCoords = false; private boolean canDragDown = true; private boolean zoomAnimation = false; private boolean discardTap = false; private int switchImageAfterAnimation = 0; private VelocityTracker velocityTracker = null; private Scroller scroller = null; private ArrayList<MessageObject> imagesArrTemp = new ArrayList<>(); private HashMap<Integer, MessageObject>[] imagesByIdsTemp = new HashMap[] { new HashMap<>(), new HashMap<>() }; private ArrayList<MessageObject> imagesArr = new ArrayList<>(); private HashMap<Integer, MessageObject>[] imagesByIds = new HashMap[] { new HashMap<>(), new HashMap<>() }; private ArrayList<TLRPC.FileLocation> imagesArrLocations = new ArrayList<>(); private ArrayList<TLRPC.Photo> avatarsArr = new ArrayList<>(); private ArrayList<Integer> imagesArrLocationsSizes = new ArrayList<>(); private ArrayList<Object> imagesArrLocals = new ArrayList<>(); private TLRPC.FileLocation currentUserAvatarLocation = null; private final static int gallery_menu_save = 1; private final static int gallery_menu_showall = 2; private final static int gallery_menu_send = 3; private final static int gallery_menu_delete = 6; private final static int gallery_menu_caption_done = 9; private final static int gallery_menu_share = 10; private final static int gallery_menu_openin = 11; private final static int gallery_menu_mute = 12; private final static int gallery_menu_masks = 13; private static DecelerateInterpolator decelerateInterpolator = null; private static Paint progressPaint = null; private class BackgroundDrawable extends ColorDrawable { private Runnable drawRunnable; public BackgroundDrawable(int color) { super(color); } @Override public void setAlpha(int alpha) { if (parentActivity instanceof LaunchActivity) { ((LaunchActivity) parentActivity).drawerLayoutContainer .setAllowDrawContent(!isVisible || alpha != 255); } super.setAlpha(alpha); } @Override public void draw(Canvas canvas) { super.draw(canvas); if (getAlpha() != 0) { if (drawRunnable != null) { drawRunnable.run(); drawRunnable = null; } } } } private class RadialProgressView { private long lastUpdateTime = 0; private float radOffset = 0; private float currentProgress = 0; private float animationProgressStart = 0; private long currentProgressTime = 0; private float animatedProgressValue = 0; private RectF progressRect = new RectF(); private int backgroundState = -1; private View parent = null; private int size = AndroidUtilities.dp(64); private int previousBackgroundState = -2; private float animatedAlphaValue = 1.0f; private float alpha = 1.0f; private float scale = 1.0f; public RadialProgressView(Context context, View parentView) { if (decelerateInterpolator == null) { decelerateInterpolator = new DecelerateInterpolator(1.5f); progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setStrokeCap(Paint.Cap.ROUND); progressPaint.setStrokeWidth(AndroidUtilities.dp(3)); progressPaint.setColor(0xffffffff); } parent = parentView; } private void updateAnimation() { long newTime = System.currentTimeMillis(); long dt = newTime - lastUpdateTime; lastUpdateTime = newTime; if (animatedProgressValue != 1) { radOffset += 360 * dt / 3000.0f; float progressDiff = currentProgress - animationProgressStart; if (progressDiff > 0) { currentProgressTime += dt; if (currentProgressTime >= 300) { animatedProgressValue = currentProgress; animationProgressStart = currentProgress; currentProgressTime = 0; } else { animatedProgressValue = animationProgressStart + progressDiff * decelerateInterpolator.getInterpolation(currentProgressTime / 300.0f); } } parent.invalidate(); } if (animatedProgressValue >= 1 && previousBackgroundState != -2) { animatedAlphaValue -= dt / 200.0f; if (animatedAlphaValue <= 0) { animatedAlphaValue = 0.0f; previousBackgroundState = -2; } parent.invalidate(); } } public void setProgress(float value, boolean animated) { if (!animated) { animatedProgressValue = value; animationProgressStart = value; } else { animationProgressStart = animatedProgressValue; } currentProgress = value; currentProgressTime = 0; } public void setBackgroundState(int state, boolean animated) { lastUpdateTime = System.currentTimeMillis(); if (animated && backgroundState != state) { previousBackgroundState = backgroundState; animatedAlphaValue = 1.0f; } else { previousBackgroundState = -2; } backgroundState = state; parent.invalidate(); } public void setAlpha(float value) { alpha = value; } public void setScale(float value) { scale = value; } public void onDraw(Canvas canvas) { int sizeScaled = (int) (size * scale); int x = (getContainerViewWidth() - sizeScaled) / 2; int y = (getContainerViewHeight() - sizeScaled) / 2; if (previousBackgroundState >= 0 && previousBackgroundState < 4) { Drawable drawable = progressDrawables[previousBackgroundState]; if (drawable != null) { drawable.setAlpha((int) (255 * animatedAlphaValue * alpha)); drawable.setBounds(x, y, x + sizeScaled, y + sizeScaled); drawable.draw(canvas); } } if (backgroundState >= 0 && backgroundState < 4) { Drawable drawable = progressDrawables[backgroundState]; if (drawable != null) { if (previousBackgroundState != -2) { drawable.setAlpha((int) (255 * (1.0f - animatedAlphaValue) * alpha)); } else { drawable.setAlpha((int) (255 * alpha)); } drawable.setBounds(x, y, x + sizeScaled, y + sizeScaled); drawable.draw(canvas); } } if (backgroundState == 0 || backgroundState == 1 || previousBackgroundState == 0 || previousBackgroundState == 1) { int diff = AndroidUtilities.dp(4); if (previousBackgroundState != -2) { progressPaint.setAlpha((int) (255 * animatedAlphaValue * alpha)); } else { progressPaint.setAlpha((int) (255 * alpha)); } progressRect.set(x + diff, y + diff, x + sizeScaled - diff, y + sizeScaled - diff); canvas.drawArc(progressRect, -90 + radOffset, Math.max(4, 360 * animatedProgressValue), false, progressPaint); updateAnimation(); } } } public static class PlaceProviderObject { public ImageReceiver imageReceiver; public int viewX; public int viewY; public View parentView; public Bitmap thumb; public int dialogId; public int index; public int size; public int radius; public int clipBottomAddition; public int clipTopAddition; public float scale = 1.0f; } public static class EmptyPhotoViewerProvider implements PhotoViewerProvider { @Override public PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { return null; } @Override public Bitmap getThumbForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { return null; } @Override public void willSwitchFromPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { } @Override public void willHidePhotoViewer() { } @Override public boolean isPhotoChecked(int index) { return false; } @Override public void setPhotoChecked(int index) { } @Override public boolean cancelButtonPressed() { return true; } @Override public void sendButtonPressed(int index) { } @Override public int getSelectedCount() { return 0; } @Override public void updatePhotoAtIndex(int index) { } @Override public boolean allowCaption() { return true; } @Override public boolean scaleToFill() { return false; } } public interface PhotoViewerProvider { PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index); Bitmap getThumbForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index); void willSwitchFromPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index); void willHidePhotoViewer(); boolean isPhotoChecked(int index); void setPhotoChecked(int index); boolean cancelButtonPressed(); void sendButtonPressed(int index); int getSelectedCount(); void updatePhotoAtIndex(int index); boolean allowCaption(); boolean scaleToFill(); } private class FrameLayoutDrawer extends SizeNotifierFrameLayoutPhoto { private Paint paint = new Paint(); public FrameLayoutDrawer(Context context) { super(context); setWillNotDraw(false); paint.setColor(0x33000000); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(widthSize, heightSize); measureChildWithMargins(captionEditText, widthMeasureSpec, 0, heightMeasureSpec, 0); int inputFieldHeight = captionEditText.getMeasuredHeight(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child.getVisibility() == GONE || child == captionEditText) { continue; } if (captionEditText.isPopupView(child)) { if (AndroidUtilities.isInMultiwindow) { if (AndroidUtilities.isTablet()) { child.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec( Math.min(AndroidUtilities.dp(320), heightSize - inputFieldHeight - AndroidUtilities.statusBarHeight), MeasureSpec.EXACTLY)); } else { child.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec( heightSize - inputFieldHeight - AndroidUtilities.statusBarHeight, MeasureSpec.EXACTLY)); } } else { child.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(child.getLayoutParams().height, MeasureSpec.EXACTLY)); } } else { measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); } } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); int paddingBottom = getKeyboardHeight() <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow ? captionEditText.getEmojiPadding() : 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final int width = child.getMeasuredWidth(); final int height = child.getMeasuredHeight(); int childLeft; int childTop; int gravity = lp.gravity; if (gravity == -1) { gravity = Gravity.TOP | Gravity.LEFT; } final int absoluteGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK; final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.CENTER_HORIZONTAL: childLeft = (r - l - width) / 2 + lp.leftMargin - lp.rightMargin; break; case Gravity.RIGHT: childLeft = r - width - lp.rightMargin; break; case Gravity.LEFT: default: childLeft = lp.leftMargin; } switch (verticalGravity) { case Gravity.TOP: childTop = lp.topMargin; break; case Gravity.CENTER_VERTICAL: childTop = ((b - paddingBottom) - t - height) / 2 + lp.topMargin - lp.bottomMargin; break; case Gravity.BOTTOM: childTop = ((b - paddingBottom) - t) - height - lp.bottomMargin; break; default: childTop = lp.topMargin; } if (child == mentionListView) { if (!captionEditText.isPopupShowing() && !captionEditText.isKeyboardVisible() && captionEditText.getEmojiPadding() == 0) { childTop += AndroidUtilities.dp(400); } else { childTop -= captionEditText.getMeasuredHeight(); } } else if (child == captionEditText) { if (!captionEditText.isPopupShowing() && !captionEditText.isKeyboardVisible() && captionEditText.getEmojiPadding() == 0) { childTop += AndroidUtilities.dp(400); } } else if (child == pickerView || child == captionTextViewNew || child == captionTextViewOld) { if (captionEditText.isPopupShowing() || captionEditText.isKeyboardVisible()) { childTop += AndroidUtilities.dp(400); } } else if (captionEditText.isPopupView(child)) { if (AndroidUtilities.isInMultiwindow) { childTop = captionEditText.getTop() - child.getMeasuredHeight() + AndroidUtilities.dp(1); } else { childTop = captionEditText.getBottom(); } } child.layout(childLeft, childTop, childLeft + width, childTop + height); } notifyHeightChanged(); } @Override protected void onDraw(Canvas canvas) { getInstance().onDraw(canvas); if (Build.VERSION.SDK_INT >= 21 && AndroidUtilities.statusBarHeight != 0) { canvas.drawRect(0, 0, getMeasuredWidth(), AndroidUtilities.statusBarHeight, paint); } } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return child != aspectRatioFrameLayout && super.drawChild(canvas, child, drawingTime); } } 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 PhotoViewer() { blackPaint.setColor(0xff000000); } @SuppressWarnings("unchecked") @Override public void didReceivedNotification(int id, Object... args) { if (id == NotificationCenter.FileDidFailedLoad) { String location = (String) args[0]; for (int a = 0; a < 3; a++) { if (currentFileNames[a] != null && currentFileNames[a].equals(location)) { radialProgressViews[a].setProgress(1.0f, true); checkProgress(a, true); break; } } } else if (id == NotificationCenter.FileDidLoaded) { String location = (String) args[0]; for (int a = 0; a < 3; a++) { if (currentFileNames[a] != null && currentFileNames[a].equals(location)) { radialProgressViews[a].setProgress(1.0f, true); checkProgress(a, true); if (Build.VERSION.SDK_INT >= 16 && a == 0 && (currentMessageObject != null && currentMessageObject.isVideo() || currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document)))) { onActionClick(false); } break; } } } else if (id == NotificationCenter.FileLoadProgressChanged) { String location = (String) args[0]; for (int a = 0; a < 3; a++) { if (currentFileNames[a] != null && currentFileNames[a].equals(location)) { Float progress = (Float) args[1]; radialProgressViews[a].setProgress(progress, true); } } } else if (id == NotificationCenter.dialogPhotosLoaded) { int guid = (Integer) args[4]; int did = (Integer) args[0]; if (avatarsDialogId == did && classGuid == guid) { boolean fromCache = (Boolean) args[3]; int setToImage = -1; ArrayList<TLRPC.Photo> photos = (ArrayList<TLRPC.Photo>) args[5]; if (photos.isEmpty()) { return; } imagesArrLocations.clear(); imagesArrLocationsSizes.clear(); avatarsArr.clear(); for (int a = 0; a < photos.size(); a++) { TLRPC.Photo photo = photos.get(a); if (photo == null || photo instanceof TLRPC.TL_photoEmpty || photo.sizes == null) { continue; } TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 640); if (sizeFull != null) { if (setToImage == -1 && currentFileLocation != null) { for (int b = 0; b < photo.sizes.size(); b++) { TLRPC.PhotoSize size = photo.sizes.get(b); if (size.location.local_id == currentFileLocation.local_id && size.location.volume_id == currentFileLocation.volume_id) { setToImage = imagesArrLocations.size(); break; } } } imagesArrLocations.add(sizeFull.location); imagesArrLocationsSizes.add(sizeFull.size); avatarsArr.add(photo); } } if (!avatarsArr.isEmpty()) { menuItem.showSubItem(gallery_menu_delete); } else { menuItem.hideSubItem(gallery_menu_delete); } needSearchImageInArr = false; currentIndex = -1; if (setToImage != -1) { setImageIndex(setToImage, true); } else { avatarsArr.add(0, new TLRPC.TL_photoEmpty()); imagesArrLocations.add(0, currentFileLocation); imagesArrLocationsSizes.add(0, 0); setImageIndex(0, true); } if (fromCache) { MessagesController.getInstance().loadDialogPhotos(avatarsDialogId, 0, 80, 0, false, classGuid); } } } else if (id == NotificationCenter.mediaCountDidLoaded) { long uid = (Long) args[0]; if (uid == currentDialogId || uid == mergeDialogId) { if (uid == currentDialogId) { totalImagesCount = (Integer) args[1]; /*if ((Boolean) args[2]) { SharedMediaQuery.getMediaCount(currentDialogId, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, false); }*/ } else if (uid == mergeDialogId) { totalImagesCountMerge = (Integer) args[1]; /*if ((Boolean) args[2]) { SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, false); }*/ } if (needSearchImageInArr && isFirstLoading) { isFirstLoading = false; loadingMoreImages = true; SharedMediaQuery.loadMedia(currentDialogId, 0, 80, 0, SharedMediaQuery.MEDIA_PHOTOVIDEO, true, classGuid); } else if (!imagesArr.isEmpty()) { if (opennedFromMedia) { actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, currentIndex + 1, totalImagesCount + totalImagesCountMerge)); } else { actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, (totalImagesCount + totalImagesCountMerge - imagesArr.size()) + currentIndex + 1, totalImagesCount + totalImagesCountMerge)); } } } } else if (id == NotificationCenter.mediaDidLoaded) { long uid = (Long) args[0]; int guid = (Integer) args[3]; if ((uid == currentDialogId || uid == mergeDialogId) && guid == classGuid) { loadingMoreImages = false; int loadIndex = uid == currentDialogId ? 0 : 1; ArrayList<MessageObject> arr = (ArrayList<MessageObject>) args[2]; endReached[loadIndex] = (Boolean) args[5]; if (needSearchImageInArr) { if (arr.isEmpty() && (loadIndex != 0 || mergeDialogId == 0)) { needSearchImageInArr = false; return; } int foundIndex = -1; MessageObject currentMessage = imagesArr.get(currentIndex); int added = 0; for (int a = 0; a < arr.size(); a++) { MessageObject message = arr.get(a); if (!imagesByIdsTemp[loadIndex].containsKey(message.getId())) { imagesByIdsTemp[loadIndex].put(message.getId(), message); if (opennedFromMedia) { imagesArrTemp.add(message); if (message.getId() == currentMessage.getId()) { foundIndex = added; } added++; } else { added++; imagesArrTemp.add(0, message); if (message.getId() == currentMessage.getId()) { foundIndex = arr.size() - added; } } } } if (added == 0 && (loadIndex != 0 || mergeDialogId == 0)) { totalImagesCount = imagesArr.size(); totalImagesCountMerge = 0; } if (foundIndex != -1) { imagesArr.clear(); imagesArr.addAll(imagesArrTemp); for (int a = 0; a < 2; a++) { imagesByIds[a].clear(); imagesByIds[a].putAll(imagesByIdsTemp[a]); imagesByIdsTemp[a].clear(); } imagesArrTemp.clear(); needSearchImageInArr = false; currentIndex = -1; if (foundIndex >= imagesArr.size()) { foundIndex = imagesArr.size() - 1; } setImageIndex(foundIndex, true); } else { int loadFromMaxId; if (opennedFromMedia) { loadFromMaxId = imagesArrTemp.isEmpty() ? 0 : imagesArrTemp.get(imagesArrTemp.size() - 1).getId(); if (loadIndex == 0 && endReached[loadIndex] && mergeDialogId != 0) { loadIndex = 1; if (!imagesArrTemp.isEmpty() && imagesArrTemp.get(imagesArrTemp.size() - 1) .getDialogId() != mergeDialogId) { loadFromMaxId = 0; } } } else { loadFromMaxId = imagesArrTemp.isEmpty() ? 0 : imagesArrTemp.get(0).getId(); if (loadIndex == 0 && endReached[loadIndex] && mergeDialogId != 0) { loadIndex = 1; if (!imagesArrTemp.isEmpty() && imagesArrTemp.get(0).getDialogId() != mergeDialogId) { loadFromMaxId = 0; } } } if (!endReached[loadIndex]) { loadingMoreImages = true; if (opennedFromMedia) { SharedMediaQuery.loadMedia(loadIndex == 0 ? currentDialogId : mergeDialogId, 0, 80, loadFromMaxId, SharedMediaQuery.MEDIA_PHOTOVIDEO, true, classGuid); } else { SharedMediaQuery.loadMedia(loadIndex == 0 ? currentDialogId : mergeDialogId, 0, 80, loadFromMaxId, SharedMediaQuery.MEDIA_PHOTOVIDEO, true, classGuid); } } } } else { int added = 0; for (MessageObject message : arr) { if (!imagesByIds[loadIndex].containsKey(message.getId())) { added++; if (opennedFromMedia) { imagesArr.add(message); } else { imagesArr.add(0, message); } imagesByIds[loadIndex].put(message.getId(), message); } } if (opennedFromMedia) { if (added == 0) { totalImagesCount = imagesArr.size(); totalImagesCountMerge = 0; } } else { if (added != 0) { int index = currentIndex; currentIndex = -1; setImageIndex(index + added, true); } else { totalImagesCount = imagesArr.size(); totalImagesCountMerge = 0; } } } } } else if (id == NotificationCenter.emojiDidLoaded) { if (captionTextView != null) { captionTextView.invalidate(); } } } private void onSharePressed() { if (parentActivity == null || !allowShare) { return; } try { File f = null; boolean isVideo = false; if (currentMessageObject != null) { isVideo = currentMessageObject.isVideo(); /*if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { AndroidUtilities.openUrl(parentActivity, currentMessageObject.messageOwner.media.webpage.url); return; }*/ f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); } else if (currentFileLocation != null) { f = FileLoader.getPathToAttach(currentFileLocation, avatarsDialogId != 0); } if (f.exists()) { Intent intent = new Intent(Intent.ACTION_SEND); if (isVideo) { intent.setType("video/mp4"); } else { intent.setType("image/jpeg"); } intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f)); parentActivity.startActivityForResult( Intent.createChooser(intent, LocaleController.getString("ShareFile", R.string.ShareFile)), 500); } else { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); builder.setMessage(LocaleController.getString("PleaseDownload", R.string.PleaseDownload)); showAlertDialog(builder); } } catch (Exception e) { FileLog.e("tmessages", e); } } private void setScaleToFill() { float bitmapWidth = centerImage.getBitmapWidth(); float containerWidth = getContainerViewWidth(); float bitmapHeight = centerImage.getBitmapHeight(); float containerHeight = getContainerViewHeight(); float scaleFit = Math.min(containerHeight / bitmapHeight, containerWidth / bitmapWidth); float width = (int) (bitmapWidth * scaleFit); float height = (int) (bitmapHeight * scaleFit); scale = Math.max(containerWidth / width, containerHeight / height); updateMinMax(scale); } public void setParentActivity(final Activity activity) { if (parentActivity == activity) { return; } parentActivity = activity; actvityContext = new ContextThemeWrapper(parentActivity, R.style.Theme_TMessages); if (progressDrawables == null) { progressDrawables = new Drawable[4]; progressDrawables[0] = parentActivity.getResources().getDrawable(R.drawable.circle_big); progressDrawables[1] = parentActivity.getResources().getDrawable(R.drawable.cancel_big); progressDrawables[2] = parentActivity.getResources().getDrawable(R.drawable.load_big); progressDrawables[3] = parentActivity.getResources().getDrawable(R.drawable.play_big); } scroller = new Scroller(activity); windowView = new FrameLayout(activity) { private Runnable attachRunnable; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return isVisible && super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { return isVisible && PhotoViewer.this.onTouchEvent(event); } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean result = super.drawChild(canvas, child, drawingTime); if (Build.VERSION.SDK_INT >= 21 && child == animatingImageView && lastInsets != null) { WindowInsets insets = (WindowInsets) lastInsets; canvas.drawRect(0, getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight() + insets.getSystemWindowInsetBottom(), blackPaint); } return result; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); if (Build.VERSION.SDK_INT >= 21 && lastInsets != null) { WindowInsets insets = (WindowInsets) lastInsets; if (AndroidUtilities.incorrectDisplaySizeFix) { if (heightSize > AndroidUtilities.displaySize.y) { heightSize = AndroidUtilities.displaySize.y; } heightSize += AndroidUtilities.statusBarHeight; } heightSize -= insets.getSystemWindowInsetBottom(); widthSize -= insets.getSystemWindowInsetRight(); } else { if (heightSize > AndroidUtilities.displaySize.y) { heightSize = AndroidUtilities.displaySize.y; } } setMeasuredDimension(widthSize, heightSize); ViewGroup.LayoutParams layoutParams = animatingImageView.getLayoutParams(); animatingImageView.measure(MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.AT_MOST)); containerView.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY)); } @SuppressWarnings("DrawAllocation") @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { animatingImageView.layout(0, 0, animatingImageView.getMeasuredWidth(), animatingImageView.getMeasuredHeight()); containerView.layout(0, 0, containerView.getMeasuredWidth(), containerView.getMeasuredHeight()); wasLayout = true; if (changed) { if (!dontResetZoomOnFirstLayout) { scale = 1; translationX = 0; translationY = 0; updateMinMax(scale); } if (checkImageView != null) { checkImageView.post(new Runnable() { @Override public void run() { FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) checkImageView .getLayoutParams(); WindowManager manager = (WindowManager) ApplicationLoader.applicationContext .getSystemService(Activity.WINDOW_SERVICE); int rotation = manager.getDefaultDisplay().getRotation(); layoutParams.topMargin = AndroidUtilities .dp(rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90 ? 58 : 68) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); checkImageView.setLayoutParams(layoutParams); } }); } } if (dontResetZoomOnFirstLayout) { setScaleToFill(); dontResetZoomOnFirstLayout = false; } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); attachedToWindow = true; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); attachedToWindow = false; wasLayout = false; } @Override public boolean dispatchKeyEventPreIme(KeyEvent event) { if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { if (captionEditText.isPopupShowing() || captionEditText.isKeyboardVisible()) { closeCaptionEnter(false); return false; } PhotoViewer.getInstance().closePhoto(true, false); return true; } return super.dispatchKeyEventPreIme(event); } @Override public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback, int type) { if (Build.VERSION.SDK_INT >= 23) { View view = parentActivity.findViewById(android.R.id.content); if (view instanceof ViewGroup) { try { return ((ViewGroup) view).startActionModeForChild(originalView, callback, type); } catch (Throwable e) { FileLog.e("tmessages", e); } } } return super.startActionModeForChild(originalView, callback, type); } }; windowView.setBackgroundDrawable(backgroundDrawable); windowView.setClipChildren(true); windowView.setFocusable(false); animatingImageView = new ClippingImageView(activity); animatingImageView.setAnimationValues(animationValues); windowView.addView(animatingImageView, LayoutHelper.createFrame(40, 40)); containerView = new FrameLayoutDrawer(activity); containerView.setFocusable(false); windowView.addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); if (Build.VERSION.SDK_INT >= 21) { //containerView.setFitsSystemWindows(true); containerView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @SuppressLint("NewApi") @Override public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { lastInsets = insets; windowView.requestLayout(); return insets.consumeSystemWindowInsets(); } }); //containerView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);*/ } windowLayoutParams = new WindowManager.LayoutParams(); windowLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; windowLayoutParams.format = PixelFormat.TRANSLUCENT; windowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; windowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT; windowLayoutParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; if (Build.VERSION.SDK_INT >= 21) { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } else { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; } actionBar = new ActionBar(activity); actionBar.setBackgroundColor(Theme.ACTION_BAR_PHOTO_VIEWER_COLOR); actionBar.setOccupyStatusBar(Build.VERSION.SDK_INT >= 21); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR); actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, 1, 1)); containerView.addView(actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { if (id == -1) { if (needCaptionLayout && (captionEditText.isPopupShowing() || captionEditText.isKeyboardVisible())) { closeCaptionEnter(false); return; } closePhoto(true, false); } else if (id == gallery_menu_save) { if (Build.VERSION.SDK_INT >= 23 && parentActivity.checkSelfPermission( Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { parentActivity .requestPermissions(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, 4); return; } File f = null; if (currentMessageObject != null) { f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); } else if (currentFileLocation != null) { f = FileLoader.getPathToAttach(currentFileLocation, avatarsDialogId != 0); } if (f != null && f.exists()) { MediaController.saveFile(f.toString(), parentActivity, currentMessageObject != null && currentMessageObject.isVideo() ? 1 : 0, null, null); } else { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); builder.setMessage(LocaleController.getString("PleaseDownload", R.string.PleaseDownload)); showAlertDialog(builder); } } else if (id == gallery_menu_showall) { if (opennedFromMedia) { closePhoto(true, false); } else if (currentDialogId != 0) { disableShowCheck = true; Bundle args2 = new Bundle(); args2.putLong("dialog_id", currentDialogId); MediaActivity mediaActivity = new MediaActivity(args2); if (parentChatActivity != null) { mediaActivity.setChatInfo(parentChatActivity.getCurrentChatInfo()); } closePhoto(false, false); ((LaunchActivity) parentActivity).presentFragment(mediaActivity, false, true); } } else if (id == gallery_menu_send) { /*Intent intent = new Intent(this, MessagesActivity.class); intent.putExtra("onlySelect", true); startActivityForResult(intent, 10); if (requestCode == 10) { int chatId = data.getIntExtra("chatId", 0); int userId = data.getIntExtra("userId", 0); int dialog_id = 0; if (chatId != 0) { dialog_id = -chatId; } else if (userId != 0) { dialog_id = userId; } TLRPC.FileLocation location = getCurrentFile(); if (dialog_id != 0 && location != null) { Intent intent = new Intent(GalleryImageViewer.this, ChatActivity.class); if (chatId != 0) { intent.putExtra("chatId", chatId); } else { intent.putExtra("userId", userId); } startActivity(intent); NotificationCenter.getInstance().postNotificationName(MessagesController.closeChats); finish(); if (withoutBottom) { MessagesController.getInstance().sendMessage(location, dialog_id); } else { int item = mViewPager.getCurrentItem(); MessageObject obj = localPagerAdapter.imagesArr.get(item); MessagesController.getInstance().sendMessage(obj, dialog_id); } } }*/ } else if (id == gallery_menu_delete) { if (parentActivity == null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); if (currentMessageObject != null && currentMessageObject.isVideo()) { builder.setMessage(LocaleController.formatString("AreYouSureDeleteVideo", R.string.AreYouSureDeleteVideo)); } else if (currentMessageObject != null && currentMessageObject.isGif()) { builder.setMessage(LocaleController.formatString("AreYouSure", R.string.AreYouSure)); } else { builder.setMessage(LocaleController.formatString("AreYouSureDeletePhoto", R.string.AreYouSureDeletePhoto)); } builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { if (!imagesArr.isEmpty()) { if (currentIndex < 0 || currentIndex >= imagesArr.size()) { return; } MessageObject obj = imagesArr.get(currentIndex); if (obj.isSent()) { closePhoto(false, false); ArrayList<Integer> arr = new ArrayList<>(); arr.add(obj.getId()); ArrayList<Long> random_ids = null; TLRPC.EncryptedChat encryptedChat = null; if ((int) obj.getDialogId() == 0 && obj.messageOwner.random_id != 0) { random_ids = new ArrayList<>(); random_ids.add(obj.messageOwner.random_id); encryptedChat = MessagesController.getInstance() .getEncryptedChat((int) (obj.getDialogId() >> 32)); } MessagesController.getInstance().deleteMessages(arr, random_ids, encryptedChat, obj.messageOwner.to_id.channel_id); } } else if (!avatarsArr.isEmpty()) { if (currentIndex < 0 || currentIndex >= avatarsArr.size()) { return; } TLRPC.Photo photo = avatarsArr.get(currentIndex); TLRPC.FileLocation currentLocation = imagesArrLocations.get(currentIndex); if (photo instanceof TLRPC.TL_photoEmpty) { photo = null; } boolean current = false; if (currentUserAvatarLocation != null) { if (photo != null) { for (TLRPC.PhotoSize size : photo.sizes) { if (size.location.local_id == currentUserAvatarLocation.local_id && size.location.volume_id == currentUserAvatarLocation.volume_id) { current = true; break; } } } else if (currentLocation.local_id == currentUserAvatarLocation.local_id && currentLocation.volume_id == currentUserAvatarLocation.volume_id) { current = true; } } if (current) { MessagesController.getInstance().deleteUserPhoto(null); closePhoto(false, false); } else if (photo != null) { TLRPC.TL_inputPhoto inputPhoto = new TLRPC.TL_inputPhoto(); inputPhoto.id = photo.id; inputPhoto.access_hash = photo.access_hash; MessagesController.getInstance().deleteUserPhoto(inputPhoto); MessagesStorage.getInstance().clearUserPhoto(avatarsDialogId, photo.id); imagesArrLocations.remove(currentIndex); imagesArrLocationsSizes.remove(currentIndex); avatarsArr.remove(currentIndex); if (imagesArrLocations.isEmpty()) { closePhoto(false, false); } else { int index = currentIndex; if (index >= avatarsArr.size()) { index = avatarsArr.size() - 1; } currentIndex = -1; setImageIndex(index, true); } } } } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showAlertDialog(builder); } else if (id == gallery_menu_caption_done) { closeCaptionEnter(true); } else if (id == gallery_menu_share) { onSharePressed(); } else if (id == gallery_menu_openin) { try { AndroidUtilities.openForView(currentMessageObject, parentActivity); closePhoto(false, false); } catch (Exception e) { FileLog.e("tmessages", e); } } else if (id == gallery_menu_mute) { muteVideo = !muteVideo; if (videoPlayer != null) { videoPlayer.setMute(muteVideo); } if (muteVideo) { actionBar.setTitle(LocaleController.getString("AttachGif", R.string.AttachGif)); muteItem.setIcon(R.drawable.volume_off); } else { actionBar.setTitle(LocaleController.getString("AttachVideo", R.string.AttachVideo)); muteItem.setIcon(R.drawable.volume_on); } } else if (id == gallery_menu_masks) { if (parentActivity == null || currentMessageObject == null || currentMessageObject.messageOwner.media == null || currentMessageObject.messageOwner.media.photo == null) { return; } StickersAlert stickersAlert = new StickersAlert(parentActivity, currentMessageObject.messageOwner.media.photo); stickersAlert.show(); } } @Override public boolean canOpenMenu() { if (currentMessageObject != null) { File f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); if (f.exists()) { return true; } } else if (currentFileLocation != null) { File f = FileLoader.getPathToAttach(currentFileLocation, avatarsDialogId != 0); if (f.exists()) { return true; } } return false; } }); ActionBarMenu menu = actionBar.createMenu(); masksItem = menu.addItem(gallery_menu_masks, R.drawable.ic_masks_msk1); muteItem = menu.addItem(gallery_menu_mute, R.drawable.volume_on); menuItem = menu.addItem(0, R.drawable.ic_ab_other); menuItem.addSubItem(gallery_menu_openin, LocaleController.getString("OpenInExternalApp", R.string.OpenInExternalApp), 0); menuItem.addSubItem(gallery_menu_showall, LocaleController.getString("ShowAllMedia", R.string.ShowAllMedia), 0); menuItem.addSubItem(gallery_menu_share, LocaleController.getString("ShareFile", R.string.ShareFile), 0); menuItem.addSubItem(gallery_menu_save, LocaleController.getString("SaveToGallery", R.string.SaveToGallery), 0); menuItem.addSubItem(gallery_menu_delete, LocaleController.getString("Delete", R.string.Delete), 0); captionDoneItem = menu.addItemWithWidth(gallery_menu_caption_done, R.drawable.ic_done, AndroidUtilities.dp(56)); bottomLayout = new FrameLayout(actvityContext); bottomLayout.setBackgroundColor(0x7f000000); containerView.addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); captionTextViewOld = new TextView(actvityContext); captionTextViewOld.setMaxLines(10); captionTextViewOld.setBackgroundColor(0x7f000000); captionTextViewOld.setPadding(AndroidUtilities.dp(20), AndroidUtilities.dp(8), AndroidUtilities.dp(20), AndroidUtilities.dp(8)); captionTextViewOld.setLinkTextColor(0xffffffff); captionTextViewOld.setTextColor(0xffffffff); captionTextViewOld.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); captionTextViewOld.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); captionTextViewOld.setVisibility(View.INVISIBLE); containerView.addView(captionTextViewOld, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 48)); captionTextViewOld.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (cropItem.getVisibility() == View.VISIBLE) { openCaptionEnter(); } } }); captionTextView = captionTextViewNew = new TextView(actvityContext); captionTextViewNew.setMaxLines(10); captionTextViewNew.setBackgroundColor(0x7f000000); captionTextViewNew.setPadding(AndroidUtilities.dp(20), AndroidUtilities.dp(8), AndroidUtilities.dp(20), AndroidUtilities.dp(8)); captionTextViewNew.setLinkTextColor(0xffffffff); captionTextViewNew.setTextColor(0xffffffff); captionTextViewNew.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); captionTextViewNew.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); captionTextViewNew.setVisibility(View.INVISIBLE); containerView.addView(captionTextViewNew, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 48)); captionTextViewNew.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (cropItem.getVisibility() == View.VISIBLE) { openCaptionEnter(); } } }); radialProgressViews[0] = new RadialProgressView(containerView.getContext(), containerView); radialProgressViews[0].setBackgroundState(0, false); radialProgressViews[1] = new RadialProgressView(containerView.getContext(), containerView); radialProgressViews[1].setBackgroundState(0, false); radialProgressViews[2] = new RadialProgressView(containerView.getContext(), containerView); radialProgressViews[2].setBackgroundState(0, false); shareButton = new ImageView(containerView.getContext()); shareButton.setImageResource(R.drawable.share); shareButton.setScaleType(ImageView.ScaleType.CENTER); shareButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); bottomLayout.addView(shareButton, LayoutHelper.createFrame(50, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); shareButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onSharePressed(); } }); nameTextView = new TextView(containerView.getContext()); nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); nameTextView.setSingleLine(true); nameTextView.setMaxLines(1); nameTextView.setEllipsize(TextUtils.TruncateAt.END); nameTextView.setTextColor(0xffffffff); nameTextView.setGravity(Gravity.LEFT); bottomLayout.addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 5, 60, 0)); dateTextView = new TextView(containerView.getContext()); dateTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); dateTextView.setSingleLine(true); dateTextView.setMaxLines(1); dateTextView.setEllipsize(TextUtils.TruncateAt.END); dateTextView.setTextColor(0xffffffff); dateTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); dateTextView.setGravity(Gravity.LEFT); bottomLayout.addView(dateTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 25, 50, 0)); if (Build.VERSION.SDK_INT >= 16) { videoPlayerSeekbar = new SeekBar(containerView.getContext()); videoPlayerSeekbar.setColors(0x66ffffff, 0xffffffff, 0xffffffff); videoPlayerSeekbar.setDelegate(new SeekBar.SeekBarDelegate() { @Override public void onSeekBarDrag(float progress) { if (videoPlayer != null) { videoPlayer.getPlayerControl().seekTo((int) (progress * videoPlayer.getDuration())); } } }); videoPlayerControlFrameLayout = new FrameLayout(containerView.getContext()) { @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); if (videoPlayerSeekbar.onTouch(event.getAction(), event.getX() - AndroidUtilities.dp(48), event.getY())) { getParent().requestDisallowInterceptTouchEvent(true); invalidate(); return true; } return super.onTouchEvent(event); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); long duration; if (videoPlayer != null) { duration = videoPlayer.getDuration(); if (duration == ExoPlayer.UNKNOWN_TIME) { duration = 0; } } else { duration = 0; } duration /= 1000; int size = (int) Math .ceil(videoPlayerTime.getPaint().measureText(String.format("%02d:%02d / %02d:%02d", duration / 60, duration % 60, duration / 60, duration % 60))); videoPlayerSeekbar.setSize(getMeasuredWidth() - AndroidUtilities.dp(48 + 16) - size, getMeasuredHeight()); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); float progress = 0; if (videoPlayer != null) { PlayerControl playerControl = videoPlayer.getPlayerControl(); progress = playerControl.getCurrentPosition() / (float) playerControl.getDuration(); } videoPlayerSeekbar.setProgress(progress); } @Override protected void onDraw(Canvas canvas) { canvas.save(); canvas.translate(AndroidUtilities.dp(48), 0); videoPlayerSeekbar.draw(canvas); canvas.restore(); } }; videoPlayerControlFrameLayout.setWillNotDraw(false); bottomLayout.addView(videoPlayerControlFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); videoPlayButton = new ImageView(containerView.getContext()); videoPlayButton.setScaleType(ImageView.ScaleType.CENTER); videoPlayerControlFrameLayout.addView(videoPlayButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); videoPlayButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (videoPlayer != null) { if (isPlaying) { videoPlayer.getPlayerControl().pause(); } else { videoPlayer.getPlayerControl().start(); } } } }); videoPlayerTime = new TextView(containerView.getContext()); videoPlayerTime.setTextColor(0xffffffff); videoPlayerTime.setGravity(Gravity.CENTER_VERTICAL); videoPlayerTime.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); videoPlayerControlFrameLayout.addView(videoPlayerTime, LayoutHelper.createFrame( LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.RIGHT | Gravity.TOP, 0, 0, 8, 0)); } pickerView = new PickerBottomLayoutViewer(actvityContext); pickerView.setBackgroundColor(0x7f000000); containerView.addView(pickerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); pickerView.cancelButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (placeProvider instanceof EmptyPhotoViewerProvider) { closePhoto(false, false); } else if (placeProvider != null) { closePhoto(!placeProvider.cancelButtonPressed(), false); } } }); pickerView.doneButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (placeProvider != null) { placeProvider.sendButtonPressed(currentIndex); closePhoto(false, false); } } }); LinearLayout itemsLayout = new LinearLayout(parentActivity); itemsLayout.setOrientation(LinearLayout.HORIZONTAL); pickerView.addView(itemsLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 48, Gravity.TOP | Gravity.CENTER_HORIZONTAL)); tuneItem = new ImageView(parentActivity); tuneItem.setScaleType(ImageView.ScaleType.CENTER); tuneItem.setImageResource(R.drawable.photo_tools); tuneItem.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); itemsLayout.addView(tuneItem, LayoutHelper.createLinear(56, 48)); tuneItem.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { switchToEditMode(2); } }); paintItem = new ImageView(parentActivity); paintItem.setScaleType(ImageView.ScaleType.CENTER); paintItem.setImageResource(R.drawable.photo_paint); paintItem.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); itemsLayout.addView(paintItem, LayoutHelper.createLinear(56, 48)); paintItem.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { switchToEditMode(3); } }); cropItem = new ImageView(parentActivity); cropItem.setScaleType(ImageView.ScaleType.CENTER); cropItem.setImageResource(R.drawable.photo_crop); cropItem.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); itemsLayout.addView(cropItem, LayoutHelper.createLinear(56, 48)); cropItem.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { switchToEditMode(1); } }); editorDoneLayout = new PickerBottomLayoutViewer(actvityContext); editorDoneLayout.setBackgroundColor(0x7f000000); editorDoneLayout.updateSelectedCount(0, false); editorDoneLayout.setVisibility(View.GONE); containerView.addView(editorDoneLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM)); editorDoneLayout.cancelButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (currentEditMode == 1) { photoCropView.cancelAnimationRunnable(); } switchToEditMode(0); } }); editorDoneLayout.doneButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (currentEditMode == 1) { photoCropView.cancelAnimationRunnable(); if (imageMoveAnimation != null) { return; } } applyCurrentEditMode(); switchToEditMode(0); } }); ImageView rotateButton = new ImageView(actvityContext); rotateButton.setScaleType(ImageView.ScaleType.CENTER); rotateButton.setImageResource(R.drawable.tool_rotate); rotateButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); editorDoneLayout.addView(rotateButton, LayoutHelper.createFrame(48, 48, Gravity.CENTER)); rotateButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { centerImage.setOrientation(centerImage.getOrientation() - 90, false); photoCropView.setOrientation(centerImage.getOrientation()); containerView.invalidate(); } }); gestureDetector = new GestureDetector(containerView.getContext(), this); gestureDetector.setOnDoubleTapListener(this); ImageReceiver.ImageReceiverDelegate imageReceiverDelegate = new ImageReceiver.ImageReceiverDelegate() { @Override public void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb) { if (imageReceiver == centerImage && set && placeProvider != null && placeProvider.scaleToFill()) { if (!wasLayout) { dontResetZoomOnFirstLayout = true; } else { setScaleToFill(); } } } }; centerImage.setParentView(containerView); centerImage.setCrossfadeAlpha((byte) 2); centerImage.setInvalidateAll(true); centerImage.setDelegate(imageReceiverDelegate); leftImage.setParentView(containerView); leftImage.setCrossfadeAlpha((byte) 2); leftImage.setInvalidateAll(true); leftImage.setDelegate(imageReceiverDelegate); rightImage.setParentView(containerView); rightImage.setCrossfadeAlpha((byte) 2); rightImage.setInvalidateAll(true); rightImage.setDelegate(imageReceiverDelegate); WindowManager manager = (WindowManager) ApplicationLoader.applicationContext .getSystemService(Activity.WINDOW_SERVICE); int rotation = manager.getDefaultDisplay().getRotation(); checkImageView = new CheckBox(containerView.getContext(), R.drawable.selectphoto_large); checkImageView.setDrawBackground(true); checkImageView.setSize(45); checkImageView.setCheckOffset(AndroidUtilities.dp(1)); checkImageView.setColor(0xff3ccaef); checkImageView.setVisibility(View.GONE); containerView.addView(checkImageView, LayoutHelper.createFrame(45, 45, Gravity.RIGHT | Gravity.TOP, 0, rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90 ? 58 : 68, 10, 0)); if (Build.VERSION.SDK_INT >= 21) { ((FrameLayout.LayoutParams) checkImageView .getLayoutParams()).topMargin += AndroidUtilities.statusBarHeight; } checkImageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (placeProvider != null) { placeProvider.setPhotoChecked(currentIndex); checkImageView.setChecked(placeProvider.isPhotoChecked(currentIndex), true); updateSelectedCount(); } } }); captionEditText = new PhotoViewerCaptionEnterView(actvityContext, containerView, windowView); captionEditText.setDelegate(new PhotoViewerCaptionEnterView.PhotoViewerCaptionEnterViewDelegate() { @Override public void onCaptionEnter() { closeCaptionEnter(true); } @Override public void onTextChanged(CharSequence text) { if (mentionsAdapter != null && captionEditText != null && parentChatActivity != null && text != null) { mentionsAdapter.searchUsernameOrHashtag(text.toString(), captionEditText.getCursorPosition(), parentChatActivity.messages); } } @Override public void onWindowSizeChanged(int size) { int height = AndroidUtilities.dp(36 * Math.min(3, mentionsAdapter.getItemCount()) + (mentionsAdapter.getItemCount() > 3 ? 18 : 0)); if (size - ActionBar.getCurrentActionBarHeight() * 2 < height) { allowMentions = false; if (mentionListView != null && mentionListView.getVisibility() == View.VISIBLE) { mentionListView.setVisibility(View.INVISIBLE); } } else { allowMentions = true; if (mentionListView != null && mentionListView.getVisibility() == View.INVISIBLE) { mentionListView.setVisibility(View.VISIBLE); } } } }); containerView.addView(captionEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, -400)); mentionListView = new RecyclerListView(actvityContext); mentionListView.setTag(5); mentionLayoutManager = new LinearLayoutManager(actvityContext) { @Override public boolean supportsPredictiveItemAnimations() { return false; } }; mentionLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); mentionListView.setLayoutManager(mentionLayoutManager); mentionListView.setBackgroundColor(0x7f000000); mentionListView.setVisibility(View.GONE); mentionListView.setClipToPadding(true); mentionListView.setOverScrollMode(ListView.OVER_SCROLL_NEVER); containerView.addView(mentionListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 110, Gravity.LEFT | Gravity.BOTTOM)); mentionListView.setAdapter(mentionsAdapter = new MentionsAdapter(actvityContext, true, 0, new MentionsAdapter.MentionsAdapterDelegate() { @Override public void needChangePanelVisibility(boolean show) { if (show) { FrameLayout.LayoutParams layoutParams3 = (FrameLayout.LayoutParams) mentionListView .getLayoutParams(); int height = 36 * Math.min(3, mentionsAdapter.getItemCount()) + (mentionsAdapter.getItemCount() > 3 ? 18 : 0); layoutParams3.height = AndroidUtilities.dp(height); layoutParams3.topMargin = -AndroidUtilities.dp(height); mentionListView.setLayoutParams(layoutParams3); if (mentionListAnimation != null) { mentionListAnimation.cancel(); mentionListAnimation = null; } if (mentionListView.getVisibility() == View.VISIBLE) { mentionListView.setAlpha(1.0f); return; } else { mentionLayoutManager.scrollToPositionWithOffset(0, 10000); } if (allowMentions) { mentionListView.setVisibility(View.VISIBLE); mentionListAnimation = new AnimatorSet(); mentionListAnimation .playTogether(ObjectAnimator.ofFloat(mentionListView, "alpha", 0.0f, 1.0f)); mentionListAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { mentionListAnimation = null; } } }); mentionListAnimation.setDuration(200); mentionListAnimation.start(); } else { mentionListView.setAlpha(1.0f); mentionListView.setVisibility(View.INVISIBLE); } } else { if (mentionListAnimation != null) { mentionListAnimation.cancel(); mentionListAnimation = null; } if (mentionListView.getVisibility() == View.GONE) { return; } if (allowMentions) { mentionListAnimation = new AnimatorSet(); mentionListAnimation .playTogether(ObjectAnimator.ofFloat(mentionListView, "alpha", 0.0f)); mentionListAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { mentionListView.setVisibility(View.GONE); mentionListAnimation = null; } } }); mentionListAnimation.setDuration(200); mentionListAnimation.start(); } else { mentionListView.setVisibility(View.GONE); } } } @Override public void onContextSearch(boolean searching) { } @Override public void onContextClick(TLRPC.BotInlineResult result) { } })); mentionsAdapter.setAllowNewMentions(false); mentionListView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { @Override public void onItemClick(View view, int position) { Object object = mentionsAdapter.getItem(position); int start = mentionsAdapter.getResultStartPosition(); int len = mentionsAdapter.getResultLength(); if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; if (user != null) { captionEditText.replaceWithText(start, len, "@" + user.username + " "); } } else if (object instanceof String) { captionEditText.replaceWithText(start, len, object + " "); } } }); mentionListView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { @Override public boolean onItemClick(View view, int position) { Object object = mentionsAdapter.getItem(position); if (object instanceof String) { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); builder.setPositiveButton( LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { mentionsAdapter.clearRecentHashtags(); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showAlertDialog(builder); return true; } return false; } }); } private void openCaptionEnter() { if (imageMoveAnimation != null || changeModeAnimation != null) { return; } paintItem.setVisibility(View.GONE); cropItem.setVisibility(View.GONE); tuneItem.setVisibility(View.GONE); checkImageView.setVisibility(View.GONE); captionDoneItem.setVisibility(View.VISIBLE); pickerView.setVisibility(View.GONE); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) captionEditText.getLayoutParams(); layoutParams.bottomMargin = 0; captionEditText.setLayoutParams(layoutParams); layoutParams = (FrameLayout.LayoutParams) mentionListView.getLayoutParams(); layoutParams.bottomMargin = 0; mentionListView.setLayoutParams(layoutParams); captionTextView.setVisibility(View.INVISIBLE); captionEditText.openKeyboard(); lastTitle = actionBar.getTitle(); actionBar.setTitle(LocaleController.getString("PhotoCaption", R.string.PhotoCaption)); } private void updateVideoPlayerTime() { String newText; if (videoPlayer == null) { newText = "00:00 / 00:00"; } else { long current = videoPlayer.getCurrentPosition() / 1000; long total = videoPlayer.getDuration(); if (muteItemAvailable) { if (total >= 30000) { if (muteItem.getVisibility() == View.VISIBLE) { muteItem.setVisibility(View.GONE); } } else { if (muteItem.getVisibility() != View.VISIBLE) { muteItem.setVisibility(View.VISIBLE); } } } total /= 1000; if (total != ExoPlayer.UNKNOWN_TIME && current != ExoPlayer.UNKNOWN_TIME) { newText = String.format("%02d:%02d / %02d:%02d", current / 60, current % 60, total / 60, total % 60); } else { newText = "00:00 / 00:00"; } } if (!TextUtils.equals(videoPlayerTime.getText(), newText)) { videoPlayerTime.setText(newText); } } @SuppressLint("NewApi") private void preparePlayer(File file, boolean playWhenReady) { if (parentActivity == null) { return; } releasePlayer(); if (videoTextureView == null) { aspectRatioFrameLayout = new AspectRatioFrameLayout(parentActivity); aspectRatioFrameLayout.setVisibility(View.INVISIBLE); containerView.addView(aspectRatioFrameLayout, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER)); videoTextureView = new TextureView(parentActivity); videoTextureView.setOpaque(false); videoTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { if (videoPlayer != null) { videoPlayer.setSurface(new Surface(videoTextureView.getSurfaceTexture())); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { if (videoPlayer != null) { videoPlayer.blockingClearSurface(); } return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { if (!textureUploaded) { textureUploaded = true; containerView.invalidate(); } } }); aspectRatioFrameLayout.addView(videoTextureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER)); } textureUploaded = false; videoCrossfadeStarted = false; videoTextureView.setAlpha(videoCrossfadeAlpha = 0.0f); videoPlayButton.setImageResource(R.drawable.inline_video_play); if (videoPlayer == null) { videoPlayer = new VideoPlayer(new VideoPlayer.ExtractorRendererBuilder(parentActivity, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", Uri.fromFile(file))); videoPlayer.addListener(new VideoPlayer.Listener() { @Override public void onStateChanged(boolean playWhenReady, int playbackState) { if (videoPlayer == null) { return; } if (playbackState != VideoPlayer.STATE_ENDED && playbackState != VideoPlayer.STATE_IDLE) { try { parentActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } catch (Exception e) { FileLog.e("tmessages", e); } } else { try { parentActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } catch (Exception e) { FileLog.e("tmessages", e); } } if (playbackState == VideoPlayer.STATE_READY && aspectRatioFrameLayout.getVisibility() != View.VISIBLE) { aspectRatioFrameLayout.setVisibility(View.VISIBLE); } if (videoPlayer.getPlayerControl().isPlaying() && playbackState != VideoPlayer.STATE_ENDED) { if (!isPlaying) { isPlaying = true; videoPlayButton.setImageResource(R.drawable.inline_video_pause); AndroidUtilities.runOnUIThread(updateProgressRunnable); } } else if (isPlaying) { isPlaying = false; videoPlayButton.setImageResource(R.drawable.inline_video_play); AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); if (playbackState == VideoPlayer.STATE_ENDED) { if (!videoPlayerSeekbar.isDragging()) { videoPlayerSeekbar.setProgress(0.0f); videoPlayerControlFrameLayout.invalidate(); videoPlayer.seekTo(0); videoPlayer.getPlayerControl().pause(); } } } updateVideoPlayerTime(); } @Override public void onError(Exception e) { FileLog.e("tmessages", e); } @Override public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { if (aspectRatioFrameLayout != null) { if (unappliedRotationDegrees == 90 || unappliedRotationDegrees == 270) { int temp = width; width = height; height = temp; } aspectRatioFrameLayout.setAspectRatio( height == 0 ? 1 : (width * pixelWidthHeightRatio) / height, unappliedRotationDegrees); } } }); long duration; if (videoPlayer != null) { duration = videoPlayer.getDuration(); if (duration == ExoPlayer.UNKNOWN_TIME) { duration = 0; } } else { duration = 0; } duration /= 1000; int size = (int) Math.ceil(videoPlayerTime.getPaint().measureText(String.format("%02d:%02d / %02d:%02d", duration / 60, duration % 60, duration / 60, duration % 60))); playerNeedsPrepare = true; } if (playerNeedsPrepare) { videoPlayer.prepare(); playerNeedsPrepare = false; } if (videoPlayerControlFrameLayout != null) { if (currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document))) { bottomLayout.setVisibility(View.VISIBLE); bottomLayout.setTranslationY(-AndroidUtilities.dp(48)); } videoPlayerControlFrameLayout.setVisibility(View.VISIBLE); dateTextView.setVisibility(View.GONE); nameTextView.setVisibility(View.GONE); if (allowShare) { shareButton.setVisibility(View.GONE); menuItem.showSubItem(gallery_menu_share); } } if (videoTextureView.getSurfaceTexture() != null) { videoPlayer.setSurface(new Surface(videoTextureView.getSurfaceTexture())); } videoPlayer.setPlayWhenReady(playWhenReady); } private void releasePlayer() { if (videoPlayer != null) { videoPlayer.release(); videoPlayer = null; } try { parentActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } catch (Exception e) { FileLog.e("tmessages", e); } if (aspectRatioFrameLayout != null) { containerView.removeView(aspectRatioFrameLayout); aspectRatioFrameLayout = null; } if (videoTextureView != null) { videoTextureView = null; } if (isPlaying) { isPlaying = false; videoPlayButton.setImageResource(R.drawable.inline_video_play); AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); } if (videoPlayerControlFrameLayout != null) { videoPlayerControlFrameLayout.setVisibility(View.GONE); dateTextView.setVisibility(View.VISIBLE); nameTextView.setVisibility(View.VISIBLE); if (allowShare) { shareButton.setVisibility(View.VISIBLE); menuItem.hideSubItem(gallery_menu_share); } } } private void updateCaptionTextForCurrentPhoto(Object object) { CharSequence caption = null; if (object instanceof MediaController.PhotoEntry) { caption = ((MediaController.PhotoEntry) object).caption; } else if (object instanceof TLRPC.BotInlineResult) { //caption = ((TLRPC.BotInlineResult) object).send_message.caption; } else if (object instanceof MediaController.SearchImage) { caption = ((MediaController.SearchImage) object).caption; } if (caption == null || caption.length() == 0) { captionEditText.setFieldText(""); } else { captionEditText.setFieldText(caption); } } private void closeCaptionEnter(boolean apply) { if (currentIndex < 0 || currentIndex >= imagesArrLocals.size()) { return; } Object object = imagesArrLocals.get(currentIndex); if (apply) { if (object instanceof MediaController.PhotoEntry) { ((MediaController.PhotoEntry) object).caption = captionEditText.getFieldCharSequence(); } else if (object instanceof MediaController.SearchImage) { ((MediaController.SearchImage) object).caption = captionEditText.getFieldCharSequence(); } if (captionEditText.getFieldCharSequence().length() != 0 && !placeProvider.isPhotoChecked(currentIndex)) { placeProvider.setPhotoChecked(currentIndex); checkImageView.setChecked(placeProvider.isPhotoChecked(currentIndex), true); updateSelectedCount(); } } cropItem.setVisibility(View.VISIBLE); if (Build.VERSION.SDK_INT >= 16) { paintItem.setVisibility(View.VISIBLE); tuneItem.setVisibility(View.VISIBLE); } if (sendPhotoType == 0) { checkImageView.setVisibility(View.VISIBLE); } captionDoneItem.setVisibility(View.GONE); pickerView.setVisibility(View.VISIBLE); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) captionEditText.getLayoutParams(); layoutParams.bottomMargin = -AndroidUtilities.dp(400); captionEditText.setLayoutParams(layoutParams); layoutParams = (FrameLayout.LayoutParams) mentionListView.getLayoutParams(); layoutParams.bottomMargin = -AndroidUtilities.dp(400); mentionListView.setLayoutParams(layoutParams); if (lastTitle != null) { actionBar.setTitle(lastTitle); lastTitle = null; } updateCaptionTextForCurrentPhoto(object); setCurrentCaption(captionEditText.getFieldCharSequence()); if (captionEditText.isPopupShowing()) { captionEditText.hidePopup(); } else { captionEditText.closeKeyboard(); } } public void showAlertDialog(AlertDialog.Builder builder) { if (parentActivity == null) { return; } try { if (visibleDialog != null) { visibleDialog.dismiss(); visibleDialog = null; } } catch (Exception e) { FileLog.e("tmessages", e); } try { visibleDialog = builder.show(); visibleDialog.setCanceledOnTouchOutside(true); visibleDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { visibleDialog = null; } }); } catch (Exception e) { FileLog.e("tmessages", e); } } private void applyCurrentEditMode() { Bitmap bitmap = null; ArrayList<TLRPC.InputDocument> stickers = null; if (currentEditMode == 1) { bitmap = photoCropView.getBitmap(); } else if (currentEditMode == 2) { bitmap = photoFilterView.getBitmap(); } else if (currentEditMode == 3) { bitmap = photoPaintView.getBitmap(); stickers = photoPaintView.getMasks(); } if (bitmap != null) { TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(bitmap, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), 80, false, 101, 101); if (size != null) { Object object = imagesArrLocals.get(currentIndex); if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry entry = (MediaController.PhotoEntry) object; entry.imagePath = FileLoader.getPathToAttach(size, true).toString(); size = ImageLoader.scaleAndSaveImage(bitmap, AndroidUtilities.dp(120), AndroidUtilities.dp(120), 70, false, 101, 101); if (size != null) { entry.thumbPath = FileLoader.getPathToAttach(size, true).toString(); } if (stickers != null) { entry.stickers.addAll(stickers); } } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage entry = (MediaController.SearchImage) object; entry.imagePath = FileLoader.getPathToAttach(size, true).toString(); size = ImageLoader.scaleAndSaveImage(bitmap, AndroidUtilities.dp(120), AndroidUtilities.dp(120), 70, false, 101, 101); if (size != null) { entry.thumbPath = FileLoader.getPathToAttach(size, true).toString(); } if (stickers != null) { entry.stickers.addAll(stickers); } } if (sendPhotoType == 0 && placeProvider != null) { placeProvider.updatePhotoAtIndex(currentIndex); if (!placeProvider.isPhotoChecked(currentIndex)) { placeProvider.setPhotoChecked(currentIndex); checkImageView.setChecked(placeProvider.isPhotoChecked(currentIndex), true); updateSelectedCount(); } } if (currentEditMode == 1) { float scaleX = photoCropView.getRectSizeX() / (float) getContainerViewWidth(); float scaleY = photoCropView.getRectSizeY() / (float) getContainerViewHeight(); scale = scaleX > scaleY ? scaleX : scaleY; translationX = photoCropView.getRectX() + photoCropView.getRectSizeX() / 2 - getContainerViewWidth() / 2; translationY = photoCropView.getRectY() + photoCropView.getRectSizeY() / 2 - getContainerViewHeight() / 2; zoomAnimation = true; } centerImage.setParentView(null); centerImage.setOrientation(0, true); centerImage.setImageBitmap(bitmap); centerImage.setParentView(containerView); } } } private void switchToEditMode(final int mode) { if (currentEditMode == mode || centerImage.getBitmap() == null || changeModeAnimation != null || imageMoveAnimation != null || radialProgressViews[0].backgroundState != -1) { return; } if (mode == 0) { if (currentEditMode == 2) { if (photoFilterView.getToolsView().getVisibility() != View.VISIBLE) { photoFilterView.switchToOrFromEditMode(); return; } } Bitmap bitmap = centerImage.getBitmap(); if (bitmap != null) { int bitmapWidth = centerImage.getBitmapWidth(); int bitmapHeight = centerImage.getBitmapHeight(); float scaleX = (float) getContainerViewWidth() / (float) bitmapWidth; float scaleY = (float) getContainerViewHeight() / (float) bitmapHeight; float newScaleX = (float) getContainerViewWidth(0) / (float) bitmapWidth; float newScaleY = (float) getContainerViewHeight(0) / (float) bitmapHeight; float scale = scaleX > scaleY ? scaleY : scaleX; float newScale = newScaleX > newScaleY ? newScaleY : newScaleX; animateToScale = newScale / scale; animateToX = 0; if (currentEditMode == 1) { animateToY = AndroidUtilities.dp(24); } else if (currentEditMode == 2) { animateToY = AndroidUtilities.dp(62); } else if (currentEditMode == 3) { animateToY = (AndroidUtilities.dp(48) - ActionBar.getCurrentActionBarHeight()) / 2; } if (Build.VERSION.SDK_INT >= 21) { animateToY -= AndroidUtilities.statusBarHeight / 2; } animationStartTime = System.currentTimeMillis(); zoomAnimation = true; } imageMoveAnimation = new AnimatorSet(); if (currentEditMode == 1) { imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(editorDoneLayout, "translationY", AndroidUtilities.dp(48)), ObjectAnimator.ofFloat(PhotoViewer.this, "animationValue", 0, 1), ObjectAnimator.ofFloat(photoCropView, "alpha", 0)); } else if (currentEditMode == 2) { photoFilterView.shutdown(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(photoFilterView.getToolsView(), "translationY", AndroidUtilities.dp(126)), ObjectAnimator.ofFloat(PhotoViewer.this, "animationValue", 0, 1)); } else if (currentEditMode == 3) { photoPaintView.shutdown(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(photoPaintView.getToolsView(), "translationY", AndroidUtilities.dp(126)), ObjectAnimator.ofFloat(photoPaintView.getColorPicker(), "translationX", AndroidUtilities.dp(60)), ObjectAnimator.ofFloat(photoPaintView.getActionBar(), "translationY", -ActionBar.getCurrentActionBarHeight() - (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)), ObjectAnimator.ofFloat(PhotoViewer.this, "animationValue", 0, 1)); } imageMoveAnimation.setDuration(200); imageMoveAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { if (currentEditMode == 1) { editorDoneLayout.setVisibility(View.GONE); photoCropView.setVisibility(View.GONE); } else if (currentEditMode == 2) { containerView.removeView(photoFilterView); photoFilterView = null; } else if (currentEditMode == 3) { containerView.removeView(photoPaintView); photoPaintView = null; } imageMoveAnimation = null; currentEditMode = mode; animateToScale = 1; animateToX = 0; animateToY = 0; scale = 1; updateMinMax(scale); containerView.invalidate(); AnimatorSet animatorSet = new AnimatorSet(); ArrayList<Animator> arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, "translationY", 0)); arrayList.add(ObjectAnimator.ofFloat(actionBar, "translationY", 0)); if (needCaptionLayout) { arrayList.add(ObjectAnimator.ofFloat(captionTextView, "translationY", 0)); } if (sendPhotoType == 0) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, "alpha", 1)); } animatorSet.playTogether(arrayList); animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationStart(Animator animation) { pickerView.setVisibility(View.VISIBLE); actionBar.setVisibility(View.VISIBLE); if (needCaptionLayout) { captionTextView.setVisibility( captionTextView.getTag() != null ? View.VISIBLE : View.INVISIBLE); } if (sendPhotoType == 0) { checkImageView.setVisibility(View.VISIBLE); } } }); animatorSet.start(); } }); imageMoveAnimation.start(); } else if (mode == 1) { if (photoCropView == null) { photoCropView = new PhotoCropView(actvityContext); photoCropView.setVisibility(View.GONE); containerView.addView(photoCropView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 48)); photoCropView.setDelegate(new PhotoCropView.PhotoCropViewDelegate() { @Override public void needMoveImageTo(float x, float y, float s, boolean animated) { if (animated) { animateTo(s, x, y, true); } else { translationX = x; translationY = y; scale = s; containerView.invalidate(); } } @Override public Bitmap getBitmap() { return centerImage.getBitmap(); } }); } editorDoneLayout.doneButton.setText(LocaleController.getString("Crop", R.string.Crop)); changeModeAnimation = new AnimatorSet(); ArrayList<Animator> arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, "translationY", 0, AndroidUtilities.dp(96))); arrayList.add(ObjectAnimator.ofFloat(actionBar, "translationY", 0, -actionBar.getHeight())); if (needCaptionLayout) { arrayList.add(ObjectAnimator.ofFloat(captionTextView, "translationY", 0, AndroidUtilities.dp(96))); } if (sendPhotoType == 0) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, "alpha", 1, 0)); } changeModeAnimation.playTogether(arrayList); changeModeAnimation.setDuration(200); changeModeAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { changeModeAnimation = null; pickerView.setVisibility(View.GONE); if (needCaptionLayout) { captionTextView.setVisibility(View.INVISIBLE); } if (sendPhotoType == 0) { checkImageView.setVisibility(View.GONE); } Bitmap bitmap = centerImage.getBitmap(); if (bitmap != null) { photoCropView.setBitmap(bitmap, centerImage.getOrientation(), sendPhotoType != 1); int bitmapWidth = centerImage.getBitmapWidth(); int bitmapHeight = centerImage.getBitmapHeight(); float scaleX = (float) getContainerViewWidth() / (float) bitmapWidth; float scaleY = (float) getContainerViewHeight() / (float) bitmapHeight; float newScaleX = (float) getContainerViewWidth(1) / (float) bitmapWidth; float newScaleY = (float) getContainerViewHeight(1) / (float) bitmapHeight; float scale = scaleX > scaleY ? scaleY : scaleX; float newScale = newScaleX > newScaleY ? newScaleY : newScaleX; animateToScale = newScale / scale; animateToX = 0; animateToY = -AndroidUtilities.dp(24) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight / 2 : 0); animationStartTime = System.currentTimeMillis(); zoomAnimation = true; } imageMoveAnimation = new AnimatorSet(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(editorDoneLayout, "translationY", AndroidUtilities.dp(48), 0), ObjectAnimator.ofFloat(PhotoViewer.this, "animationValue", 0, 1), ObjectAnimator.ofFloat(photoCropView, "alpha", 0, 1)); imageMoveAnimation.setDuration(200); imageMoveAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationStart(Animator animation) { editorDoneLayout.setVisibility(View.VISIBLE); photoCropView.setVisibility(View.VISIBLE); } @Override public void onAnimationEnd(Animator animation) { imageMoveAnimation = null; currentEditMode = mode; animateToScale = 1; animateToX = 0; animateToY = 0; scale = 1; updateMinMax(scale); containerView.invalidate(); } }); imageMoveAnimation.start(); } }); changeModeAnimation.start(); } else if (mode == 2) { if (photoFilterView == null) { photoFilterView = new PhotoFilterView(parentActivity, centerImage.getBitmap(), centerImage.getOrientation()); containerView.addView(photoFilterView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); photoFilterView.getDoneTextView().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { applyCurrentEditMode(); switchToEditMode(0); } }); photoFilterView.getCancelTextView().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (photoFilterView.hasChanges()) { if (parentActivity == null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setMessage( LocaleController.getString("DiscardChanges", R.string.DiscardChanges)); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { switchToEditMode(0); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showAlertDialog(builder); } else { switchToEditMode(0); } } }); photoFilterView.getToolsView().setTranslationY(AndroidUtilities.dp(126)); } changeModeAnimation = new AnimatorSet(); ArrayList<Animator> arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, "translationY", 0, AndroidUtilities.dp(96))); arrayList.add(ObjectAnimator.ofFloat(actionBar, "translationY", 0, -actionBar.getHeight())); if (needCaptionLayout) { arrayList.add(ObjectAnimator.ofFloat(captionTextView, "translationY", 0, AndroidUtilities.dp(96))); } if (sendPhotoType == 0) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, "alpha", 1, 0)); } changeModeAnimation.playTogether(arrayList); changeModeAnimation.setDuration(200); changeModeAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { changeModeAnimation = null; pickerView.setVisibility(View.GONE); actionBar.setVisibility(View.GONE); if (needCaptionLayout) { captionTextView.setVisibility(View.INVISIBLE); } if (sendPhotoType == 0) { checkImageView.setVisibility(View.GONE); } Bitmap bitmap = centerImage.getBitmap(); if (bitmap != null) { int bitmapWidth = centerImage.getBitmapWidth(); int bitmapHeight = centerImage.getBitmapHeight(); float scaleX = (float) getContainerViewWidth() / (float) bitmapWidth; float scaleY = (float) getContainerViewHeight() / (float) bitmapHeight; float newScaleX = (float) getContainerViewWidth(2) / (float) bitmapWidth; float newScaleY = (float) getContainerViewHeight(2) / (float) bitmapHeight; float scale = scaleX > scaleY ? scaleY : scaleX; float newScale = newScaleX > newScaleY ? newScaleY : newScaleX; animateToScale = newScale / scale; animateToX = 0; animateToY = -AndroidUtilities.dp(62) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight / 2 : 0); animationStartTime = System.currentTimeMillis(); zoomAnimation = true; } imageMoveAnimation = new AnimatorSet(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(PhotoViewer.this, "animationValue", 0, 1), ObjectAnimator.ofFloat(photoFilterView.getToolsView(), "translationY", AndroidUtilities.dp(126), 0)); imageMoveAnimation.setDuration(200); imageMoveAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { photoFilterView.init(); imageMoveAnimation = null; currentEditMode = mode; animateToScale = 1; animateToX = 0; animateToY = 0; scale = 1; updateMinMax(scale); containerView.invalidate(); } }); imageMoveAnimation.start(); } }); changeModeAnimation.start(); } else if (mode == 3) { if (photoPaintView == null) { photoPaintView = new PhotoPaintView(parentActivity, centerImage.getBitmap(), centerImage.getOrientation()); containerView.addView(photoPaintView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); photoPaintView.getDoneTextView().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { applyCurrentEditMode(); switchToEditMode(0); } }); photoPaintView.getCancelTextView().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { photoPaintView.maybeShowDismissalAlert(PhotoViewer.this, parentActivity, new Runnable() { @Override public void run() { switchToEditMode(0); } }); } }); photoPaintView.getColorPicker().setTranslationX(AndroidUtilities.dp(60)); photoPaintView.getToolsView().setTranslationY(AndroidUtilities.dp(126)); photoPaintView.getActionBar().setTranslationY(-ActionBar.getCurrentActionBarHeight() - (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)); } changeModeAnimation = new AnimatorSet(); ArrayList<Animator> arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, "translationY", 0, AndroidUtilities.dp(96))); arrayList.add(ObjectAnimator.ofFloat(actionBar, "translationY", 0, -actionBar.getHeight())); if (needCaptionLayout) { arrayList.add(ObjectAnimator.ofFloat(captionTextView, "translationY", 0, AndroidUtilities.dp(96))); } if (sendPhotoType == 0) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, "alpha", 1, 0)); } changeModeAnimation.playTogether(arrayList); changeModeAnimation.setDuration(200); changeModeAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { changeModeAnimation = null; pickerView.setVisibility(View.GONE); if (needCaptionLayout) { captionTextView.setVisibility(View.INVISIBLE); } if (sendPhotoType == 0) { checkImageView.setVisibility(View.GONE); } Bitmap bitmap = centerImage.getBitmap(); if (bitmap != null) { int bitmapWidth = centerImage.getBitmapWidth(); int bitmapHeight = centerImage.getBitmapHeight(); float scaleX = (float) getContainerViewWidth() / (float) bitmapWidth; float scaleY = (float) getContainerViewHeight() / (float) bitmapHeight; float newScaleX = (float) getContainerViewWidth(3) / (float) bitmapWidth; float newScaleY = (float) getContainerViewHeight(3) / (float) bitmapHeight; float scale = scaleX > scaleY ? scaleY : scaleX; float newScale = newScaleX > newScaleY ? newScaleY : newScaleX; animateToScale = newScale / scale; animateToX = 0; animateToY = (ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(48) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) / 2; animationStartTime = System.currentTimeMillis(); zoomAnimation = true; } imageMoveAnimation = new AnimatorSet(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(PhotoViewer.this, "animationValue", 0, 1), ObjectAnimator.ofFloat(photoPaintView.getColorPicker(), "translationX", AndroidUtilities.dp(60), 0), ObjectAnimator.ofFloat(photoPaintView.getToolsView(), "translationY", AndroidUtilities.dp(126), 0), ObjectAnimator.ofFloat(photoPaintView.getActionBar(), "translationY", -ActionBar.getCurrentActionBarHeight() - (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0), 0)); imageMoveAnimation.setDuration(200); imageMoveAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { photoPaintView.init(); imageMoveAnimation = null; currentEditMode = mode; animateToScale = 1; animateToX = 0; animateToY = 0; scale = 1; updateMinMax(scale); containerView.invalidate(); } }); imageMoveAnimation.start(); } }); changeModeAnimation.start(); } } private void toggleCheckImageView(boolean show) { AnimatorSet animatorSet = new AnimatorSet(); ArrayList<Animator> arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, "alpha", show ? 1.0f : 0.0f)); if (needCaptionLayout) { arrayList.add(ObjectAnimator.ofFloat(captionTextView, "alpha", show ? 1.0f : 0.0f)); } if (sendPhotoType == 0) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, "alpha", show ? 1.0f : 0.0f)); } animatorSet.playTogether(arrayList); animatorSet.setDuration(200); animatorSet.start(); } private void toggleActionBar(boolean show, final boolean animated) { if (show) { actionBar.setVisibility(View.VISIBLE); if (canShowBottom) { bottomLayout.setVisibility(View.VISIBLE); if (captionTextView.getTag() != null) { captionTextView.setVisibility(View.VISIBLE); } } } isActionBarVisible = show; actionBar.setEnabled(show); bottomLayout.setEnabled(show); if (animated) { ArrayList<Animator> arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(actionBar, "alpha", show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(bottomLayout, "alpha", show ? 1.0f : 0.0f)); if (captionTextView.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(captionTextView, "alpha", show ? 1.0f : 0.0f)); } currentActionBarAnimation = new AnimatorSet(); currentActionBarAnimation.playTogether(arrayList); if (!show) { currentActionBarAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { if (currentActionBarAnimation != null && currentActionBarAnimation.equals(animation)) { actionBar.setVisibility(View.GONE); if (canShowBottom) { bottomLayout.setVisibility(View.GONE); if (captionTextView.getTag() != null) { captionTextView.setVisibility(View.INVISIBLE); } } currentActionBarAnimation = null; } } }); } currentActionBarAnimation.setDuration(200); currentActionBarAnimation.start(); } else { actionBar.setAlpha(show ? 1.0f : 0.0f); bottomLayout.setAlpha(show ? 1.0f : 0.0f); if (captionTextView.getTag() != null) { captionTextView.setAlpha(show ? 1.0f : 0.0f); } if (!show) { actionBar.setVisibility(View.GONE); if (canShowBottom) { bottomLayout.setVisibility(View.GONE); if (captionTextView.getTag() != null) { captionTextView.setVisibility(View.INVISIBLE); } } } } } private String getFileName(int index) { if (index < 0) { return null; } if (!imagesArrLocations.isEmpty() || !imagesArr.isEmpty()) { if (!imagesArrLocations.isEmpty()) { if (index >= imagesArrLocations.size()) { return null; } TLRPC.FileLocation location = imagesArrLocations.get(index); return location.volume_id + "_" + location.local_id + ".jpg"; } else if (!imagesArr.isEmpty()) { if (index >= imagesArr.size()) { return null; } return FileLoader.getMessageFileName(imagesArr.get(index).messageOwner); } } else if (!imagesArrLocals.isEmpty()) { if (index >= imagesArrLocals.size()) { return null; } Object object = imagesArrLocals.get(index); if (object instanceof MediaController.SearchImage) { MediaController.SearchImage searchImage = ((MediaController.SearchImage) object); if (searchImage.document != null) { return FileLoader.getAttachFileName(searchImage.document); } else if (searchImage.type != 1 && searchImage.localUrl != null && searchImage.localUrl.length() > 0) { File file = new File(searchImage.localUrl); if (file.exists()) { return file.getName(); } else { searchImage.localUrl = ""; } } return Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl, "jpg"); } else if (object instanceof TLRPC.BotInlineResult) { TLRPC.BotInlineResult botInlineResult = (TLRPC.BotInlineResult) object; if (botInlineResult.document != null) { return FileLoader.getAttachFileName(botInlineResult.document); } else if (botInlineResult.photo != null) { TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(botInlineResult.photo.sizes, AndroidUtilities.getPhotoSize()); return FileLoader.getAttachFileName(sizeFull); } else if (botInlineResult.content_url != null) { return Utilities.MD5(botInlineResult.content_url) + "." + ImageLoader.getHttpUrlExtension(botInlineResult.content_url, "jpg"); } } } return null; } private TLRPC.FileLocation getFileLocation(int index, int size[]) { if (index < 0) { return null; } if (!imagesArrLocations.isEmpty()) { if (index >= imagesArrLocations.size()) { return null; } size[0] = imagesArrLocationsSizes.get(index); return imagesArrLocations.get(index); } else if (!imagesArr.isEmpty()) { if (index >= imagesArr.size()) { return null; } MessageObject message = imagesArr.get(index); if (message.messageOwner instanceof TLRPC.TL_messageService) { if (message.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { return message.messageOwner.action.newUserPhoto.photo_big; } else { TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); if (sizeFull != null) { size[0] = sizeFull.size; if (size[0] == 0) { size[0] = -1; } return sizeFull.location; } else { size[0] = -1; } } } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && message.messageOwner.media.photo != null || message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && message.messageOwner.media.webpage != null) { TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); if (sizeFull != null) { size[0] = sizeFull.size; if (size[0] == 0) { size[0] = -1; } return sizeFull.location; } else { size[0] = -1; } } else if (message.getDocument() != null && message.getDocument().thumb != null) { size[0] = message.getDocument().thumb.size; if (size[0] == 0) { size[0] = -1; } return message.getDocument().thumb.location; } } return null; } private void updateSelectedCount() { if (placeProvider == null) { return; } pickerView.updateSelectedCount(placeProvider.getSelectedCount(), false); } private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ArrayList<MessageObject> messages, final ArrayList<Object> photos, int index, final PlaceProviderObject object) { classGuid = ConnectionsManager.getInstance().generateClassGuid(); currentMessageObject = null; currentFileLocation = null; currentPathObject = null; currentBotInlineResult = null; currentIndex = -1; currentFileNames[0] = null; currentFileNames[1] = null; currentFileNames[2] = null; avatarsDialogId = 0; totalImagesCount = 0; totalImagesCountMerge = 0; currentEditMode = 0; isFirstLoading = true; needSearchImageInArr = false; loadingMoreImages = false; endReached[0] = false; endReached[1] = mergeDialogId == 0; opennedFromMedia = false; needCaptionLayout = false; canShowBottom = true; imagesArr.clear(); imagesArrLocations.clear(); imagesArrLocationsSizes.clear(); avatarsArr.clear(); imagesArrLocals.clear(); for (int a = 0; a < 2; a++) { imagesByIds[a].clear(); imagesByIdsTemp[a].clear(); } imagesArrTemp.clear(); currentUserAvatarLocation = null; containerView.setPadding(0, 0, 0, 0); currentThumb = object != null ? object.thumb : null; menuItem.setVisibility(View.VISIBLE); bottomLayout.setVisibility(View.VISIBLE); bottomLayout.setTranslationY(0); shareButton.setVisibility(View.GONE); allowShare = false; menuItem.hideSubItem(gallery_menu_showall); menuItem.hideSubItem(gallery_menu_share); menuItem.hideSubItem(gallery_menu_openin); actionBar.setTranslationY(0); pickerView.setTranslationY(0); checkImageView.setAlpha(1.0f); pickerView.setAlpha(1.0f); checkImageView.setVisibility(View.GONE); pickerView.setVisibility(View.GONE); paintItem.setVisibility(View.GONE); cropItem.setVisibility(View.GONE); tuneItem.setVisibility(View.GONE); captionDoneItem.setVisibility(View.GONE); captionEditText.setVisibility(View.GONE); mentionListView.setVisibility(View.GONE); muteItem.setVisibility(View.GONE); masksItem.setVisibility(View.GONE); muteItemAvailable = false; muteVideo = false; muteItem.setIcon(R.drawable.volume_on); editorDoneLayout.setVisibility(View.GONE); captionTextView.setTag(null); captionTextView.setVisibility(View.INVISIBLE); if (photoCropView != null) { photoCropView.setVisibility(View.GONE); } if (photoFilterView != null) { photoFilterView.setVisibility(View.GONE); } for (int a = 0; a < 3; a++) { if (radialProgressViews[a] != null) { radialProgressViews[a].setBackgroundState(-1, false); } } if (messageObject != null && messages == null) { imagesArr.add(messageObject); if (currentAnimation != null) { needSearchImageInArr = false; } else if (!(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) && (messageObject.messageOwner.action == null || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty)) { needSearchImageInArr = true; imagesByIds[0].put(messageObject.getId(), messageObject); menuItem.showSubItem(gallery_menu_showall); } setImageIndex(0, true); } else if (fileLocation != null) { avatarsDialogId = object.dialogId; imagesArrLocations.add(fileLocation); imagesArrLocationsSizes.add(object.size); avatarsArr.add(new TLRPC.TL_photoEmpty()); shareButton.setVisibility(videoPlayerControlFrameLayout == null || videoPlayerControlFrameLayout.getVisibility() != View.VISIBLE ? View.VISIBLE : View.GONE); allowShare = true; menuItem.hideSubItem(gallery_menu_showall); if (shareButton.getVisibility() == View.VISIBLE) { menuItem.hideSubItem(gallery_menu_share); } else { menuItem.showSubItem(gallery_menu_share); } setImageIndex(0, true); currentUserAvatarLocation = fileLocation; } else if (messages != null) { menuItem.showSubItem(gallery_menu_showall); opennedFromMedia = true; imagesArr.addAll(messages); if (!opennedFromMedia) { Collections.reverse(imagesArr); index = imagesArr.size() - index - 1; } for (int a = 0; a < imagesArr.size(); a++) { MessageObject message = imagesArr.get(a); imagesByIds[message.getDialogId() == currentDialogId ? 0 : 1].put(message.getId(), message); } setImageIndex(index, true); } else if (photos != null) { if (sendPhotoType == 0) { checkImageView.setVisibility(View.VISIBLE); } menuItem.setVisibility(View.GONE); imagesArrLocals.addAll(photos); setImageIndex(index, true); pickerView.setVisibility(View.VISIBLE); bottomLayout.setVisibility(View.GONE); canShowBottom = false; Object obj = imagesArrLocals.get(index); if (obj instanceof MediaController.PhotoEntry) { if (((MediaController.PhotoEntry) obj).isVideo) { cropItem.setVisibility(View.GONE); bottomLayout.setVisibility(View.VISIBLE); bottomLayout.setTranslationY(-AndroidUtilities.dp(48)); } else { cropItem.setVisibility(View.VISIBLE); } } else if (obj instanceof TLRPC.BotInlineResult) { cropItem.setVisibility(View.GONE); } else { cropItem.setVisibility( obj instanceof MediaController.SearchImage && ((MediaController.SearchImage) obj).type == 0 ? View.VISIBLE : View.GONE); } if (parentChatActivity != null && (parentChatActivity.currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(parentChatActivity.currentEncryptedChat.layer) >= 46)) { mentionsAdapter.setChatInfo(parentChatActivity.info); mentionsAdapter.setNeedUsernames(parentChatActivity.currentChat != null); mentionsAdapter.setNeedBotContext(false); needCaptionLayout = cropItem.getVisibility() == View.VISIBLE && (placeProvider == null || placeProvider != null && placeProvider.allowCaption()); captionEditText.setVisibility(needCaptionLayout ? View.VISIBLE : View.GONE); if (captionTextView.getTag() == null && needCaptionLayout) { captionTextView.setText(LocaleController.getString("AddCaption", R.string.AddCaption)); captionTextView.setTag("empty"); captionTextView.setTextColor(0xb2ffffff); captionTextView.setVisibility(View.VISIBLE); } else { captionTextView.setTextColor(0xffffffff); } if (needCaptionLayout) { captionEditText.onCreate(); } } if (Build.VERSION.SDK_INT >= 16) { paintItem.setVisibility(cropItem.getVisibility()); tuneItem.setVisibility(cropItem.getVisibility()); } updateSelectedCount(); } if (currentAnimation == null) { if (currentDialogId != 0 && totalImagesCount == 0) { SharedMediaQuery.getMediaCount(currentDialogId, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); if (mergeDialogId != 0) { SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); } } else if (avatarsDialogId != 0) { MessagesController.getInstance().loadDialogPhotos(avatarsDialogId, 0, 80, 0, true, classGuid); } } if (currentMessageObject != null && currentMessageObject.isVideo() || currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document))) { onActionClick(false); } else if (!imagesArrLocals.isEmpty()) { Object entry = imagesArrLocals.get(index); CharSequence caption = null; if (entry instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = ((MediaController.PhotoEntry) entry); if (photoEntry.isVideo) { preparePlayer(new File(photoEntry.path), false); } } } } public boolean isMuteVideo() { return muteVideo; } private void setImages() { if (animationInProgress == 0) { setIndexToImage(centerImage, currentIndex); setIndexToImage(rightImage, currentIndex + 1); setIndexToImage(leftImage, currentIndex - 1); } } private void setImageIndex(int index, boolean init) { if (currentIndex == index || placeProvider == null) { return; } if (!init) { currentThumb = null; } currentFileNames[0] = getFileName(index); currentFileNames[1] = getFileName(index + 1); currentFileNames[2] = getFileName(index - 1); placeProvider.willSwitchFromPhoto(currentMessageObject, currentFileLocation, currentIndex); int prevIndex = currentIndex; currentIndex = index; boolean isVideo = false; boolean sameImage = false; if (!imagesArr.isEmpty()) { if (currentIndex < 0 || currentIndex >= imagesArr.size()) { closePhoto(false, false); return; } MessageObject newMessageObject = imagesArr.get(currentIndex); sameImage = currentMessageObject != null && currentMessageObject.getId() == newMessageObject.getId(); currentMessageObject = newMessageObject; isVideo = currentMessageObject.isVideo(); masksItem.setVisibility( currentMessageObject.hasPhotoStickers() && (int) currentMessageObject.getDialogId() != 0 ? View.VISIBLE : View.INVISIBLE); if (currentMessageObject.canDeleteMessage(null)) { menuItem.showSubItem(gallery_menu_delete); } else { menuItem.hideSubItem(gallery_menu_delete); } if (isVideo && Build.VERSION.SDK_INT >= 16) { menuItem.showSubItem(gallery_menu_openin); } else { menuItem.hideSubItem(gallery_menu_openin); } if (currentMessageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance() .getUser(currentMessageObject.messageOwner.from_id); if (user != null) { nameTextView.setText(UserObject.getUserName(user)); } else { nameTextView.setText(""); } } else { TLRPC.Chat chat = MessagesController.getInstance() .getChat(currentMessageObject.messageOwner.to_id.channel_id); if (chat != null) { nameTextView.setText(chat.title); } else { nameTextView.setText(""); } } long date = (long) currentMessageObject.messageOwner.date * 1000; String dateString = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(new Date(date)), LocaleController.getInstance().formatterDay.format(new Date(date))); if (currentFileNames[0] != null && isVideo) { dateTextView.setText(String.format("%s (%s)", dateString, AndroidUtilities.formatFileSize(currentMessageObject.getDocument().size))); } else { dateTextView.setText(dateString); } CharSequence caption = currentMessageObject.caption; setCurrentCaption(caption); if (currentAnimation != null) { menuItem.hideSubItem(gallery_menu_save); menuItem.hideSubItem(gallery_menu_share); if (!currentMessageObject.canDeleteMessage(null)) { menuItem.setVisibility(View.GONE); } allowShare = true; shareButton.setVisibility(View.VISIBLE); actionBar.setTitle(LocaleController.getString("AttachGif", R.string.AttachGif)); } else { if (totalImagesCount + totalImagesCountMerge != 0 && !needSearchImageInArr) { if (opennedFromMedia) { if (imagesArr.size() < totalImagesCount + totalImagesCountMerge && !loadingMoreImages && currentIndex > imagesArr.size() - 5) { int loadFromMaxId = imagesArr.isEmpty() ? 0 : imagesArr.get(imagesArr.size() - 1).getId(); int loadIndex = 0; if (endReached[loadIndex] && mergeDialogId != 0) { loadIndex = 1; if (!imagesArr.isEmpty() && imagesArr.get(imagesArr.size() - 1).getDialogId() != mergeDialogId) { loadFromMaxId = 0; } } SharedMediaQuery.loadMedia(loadIndex == 0 ? currentDialogId : mergeDialogId, 0, 80, loadFromMaxId, SharedMediaQuery.MEDIA_PHOTOVIDEO, true, classGuid); loadingMoreImages = true; } actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, currentIndex + 1, totalImagesCount + totalImagesCountMerge)); } else { if (imagesArr.size() < totalImagesCount + totalImagesCountMerge && !loadingMoreImages && currentIndex < 5) { int loadFromMaxId = imagesArr.isEmpty() ? 0 : imagesArr.get(0).getId(); int loadIndex = 0; if (endReached[loadIndex] && mergeDialogId != 0) { loadIndex = 1; if (!imagesArr.isEmpty() && imagesArr.get(0).getDialogId() != mergeDialogId) { loadFromMaxId = 0; } } SharedMediaQuery.loadMedia(loadIndex == 0 ? currentDialogId : mergeDialogId, 0, 80, loadFromMaxId, SharedMediaQuery.MEDIA_PHOTOVIDEO, true, classGuid); loadingMoreImages = true; } actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, (totalImagesCount + totalImagesCountMerge - imagesArr.size()) + currentIndex + 1, totalImagesCount + totalImagesCountMerge)); } } else if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { if (currentMessageObject.isVideo()) { actionBar.setTitle(LocaleController.getString("AttachVideo", R.string.AttachVideo)); } else { actionBar.setTitle(LocaleController.getString("AttachPhoto", R.string.AttachPhoto)); } } if (currentMessageObject.messageOwner.ttl != 0) { allowShare = false; menuItem.hideSubItem(gallery_menu_save); shareButton.setVisibility(View.GONE); menuItem.hideSubItem(gallery_menu_share); } else { allowShare = true; menuItem.showSubItem(gallery_menu_save); shareButton.setVisibility(videoPlayerControlFrameLayout == null || videoPlayerControlFrameLayout.getVisibility() != View.VISIBLE ? View.VISIBLE : View.GONE); if (shareButton.getVisibility() == View.VISIBLE) { menuItem.hideSubItem(gallery_menu_share); } else { menuItem.showSubItem(gallery_menu_share); } } } } else if (!imagesArrLocations.isEmpty()) { nameTextView.setText(""); dateTextView.setText(""); if (avatarsDialogId == UserConfig.getClientUserId() && !avatarsArr.isEmpty()) { menuItem.showSubItem(gallery_menu_delete); } else { menuItem.hideSubItem(gallery_menu_delete); } TLRPC.FileLocation old = currentFileLocation; if (index < 0 || index >= imagesArrLocations.size()) { closePhoto(false, false); return; } currentFileLocation = imagesArrLocations.get(index); if (old != null && currentFileLocation != null && old.local_id == currentFileLocation.local_id && old.volume_id == currentFileLocation.volume_id) { sameImage = true; } actionBar.setTitle( LocaleController.formatString("Of", R.string.Of, currentIndex + 1, imagesArrLocations.size())); menuItem.showSubItem(gallery_menu_save); allowShare = true; shareButton.setVisibility(videoPlayerControlFrameLayout == null || videoPlayerControlFrameLayout.getVisibility() != View.VISIBLE ? View.VISIBLE : View.GONE); if (shareButton.getVisibility() == View.VISIBLE) { menuItem.hideSubItem(gallery_menu_share); } else { menuItem.showSubItem(gallery_menu_share); } } else if (!imagesArrLocals.isEmpty()) { if (index < 0 || index >= imagesArrLocals.size()) { closePhoto(false, false); return; } Object object = imagesArrLocals.get(index); boolean fromCamera = false; CharSequence caption = null; if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = ((MediaController.PhotoEntry) object); currentPathObject = photoEntry.path; fromCamera = photoEntry.bucketId == 0 && photoEntry.dateTaken == 0 && imagesArrLocals.size() == 1; caption = photoEntry.caption; isVideo = photoEntry.isVideo; } else if (object instanceof TLRPC.BotInlineResult) { TLRPC.BotInlineResult botInlineResult = currentBotInlineResult = ((TLRPC.BotInlineResult) object); if (botInlineResult.document != null) { isVideo = MessageObject.isVideoDocument(botInlineResult.document); currentPathObject = FileLoader.getPathToAttach(botInlineResult.document).getAbsolutePath(); } else if (botInlineResult.photo != null) { TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(botInlineResult.photo.sizes, AndroidUtilities.getPhotoSize()); currentPathObject = FileLoader.getPathToAttach(sizeFull).getAbsolutePath(); } else if (botInlineResult.content_url != null) { currentPathObject = botInlineResult.content_url; isVideo = botInlineResult.type.equals("video"); } //caption = botInlineResult.send_message.caption; } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage searchImage = (MediaController.SearchImage) object; if (searchImage.document != null) { currentPathObject = FileLoader.getPathToAttach(searchImage.document, true).getAbsolutePath(); } else { currentPathObject = searchImage.imageUrl; } caption = searchImage.caption; } if (fromCamera) { if (isVideo) { muteItemAvailable = true; actionBar.setTitle(LocaleController.getString("AttachVideo", R.string.AttachVideo)); } else { actionBar.setTitle(LocaleController.getString("AttachPhoto", R.string.AttachPhoto)); } } else { actionBar.setTitle( LocaleController.formatString("Of", R.string.Of, currentIndex + 1, imagesArrLocals.size())); } if (sendPhotoType == 0) { checkImageView.setChecked(placeProvider.isPhotoChecked(currentIndex), false); } setCurrentCaption(caption); updateCaptionTextForCurrentPhoto(object); } if (currentPlaceObject != null) { if (animationInProgress == 0) { currentPlaceObject.imageReceiver.setVisible(true, true); } else { showAfterAnimation = currentPlaceObject; } } currentPlaceObject = placeProvider.getPlaceForPhoto(currentMessageObject, currentFileLocation, currentIndex); if (currentPlaceObject != null) { if (animationInProgress == 0) { currentPlaceObject.imageReceiver.setVisible(false, true); } else { hideAfterAnimation = currentPlaceObject; } } if (!sameImage) { draggingDown = false; translationX = 0; translationY = 0; scale = 1; animateToX = 0; animateToY = 0; animateToScale = 1; animationStartTime = 0; imageMoveAnimation = null; changeModeAnimation = null; if (aspectRatioFrameLayout != null) { aspectRatioFrameLayout.setVisibility(View.INVISIBLE); } releasePlayer(); pinchStartDistance = 0; pinchStartScale = 1; pinchCenterX = 0; pinchCenterY = 0; pinchStartX = 0; pinchStartY = 0; moveStartX = 0; moveStartY = 0; zooming = false; moving = false; doubleTap = false; invalidCoords = false; canDragDown = true; changingPage = false; switchImageAfterAnimation = 0; canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !isVideo && radialProgressViews[0].backgroundState != 0); updateMinMax(scale); } if (prevIndex == -1) { setImages(); for (int a = 0; a < 3; a++) { checkProgress(a, false); } } else { checkProgress(0, false); if (prevIndex > currentIndex) { ImageReceiver temp = rightImage; rightImage = centerImage; centerImage = leftImage; leftImage = temp; RadialProgressView tempProgress = radialProgressViews[0]; radialProgressViews[0] = radialProgressViews[2]; radialProgressViews[2] = tempProgress; setIndexToImage(leftImage, currentIndex - 1); checkProgress(1, false); checkProgress(2, false); } else if (prevIndex < currentIndex) { ImageReceiver temp = leftImage; leftImage = centerImage; centerImage = rightImage; rightImage = temp; RadialProgressView tempProgress = radialProgressViews[0]; radialProgressViews[0] = radialProgressViews[1]; radialProgressViews[1] = tempProgress; setIndexToImage(rightImage, currentIndex + 1); checkProgress(1, false); checkProgress(2, false); } } } private void setCurrentCaption(final CharSequence caption) { if (caption != null && caption.length() > 0) { captionTextView = captionTextViewOld; captionTextViewOld = captionTextViewNew; captionTextViewNew = captionTextView; CharSequence str = Emoji.replaceEmoji(new SpannableStringBuilder(caption.toString()), MessageObject.getTextPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); captionTextView.setTag(str); captionTextView.setText(str); captionTextView.setTextColor(0xffffffff); captionTextView.setAlpha( bottomLayout.getVisibility() == View.VISIBLE || pickerView.getVisibility() == View.VISIBLE ? 1.0f : 0.0f); AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { captionTextViewOld.setTag(null); captionTextViewOld.setVisibility(View.INVISIBLE); captionTextViewNew.setVisibility(bottomLayout.getVisibility() == View.VISIBLE || pickerView.getVisibility() == View.VISIBLE ? View.VISIBLE : View.INVISIBLE); } }); } else { if (needCaptionLayout) { captionTextView.setText(LocaleController.getString("AddCaption", R.string.AddCaption)); captionTextView.setTag("empty"); captionTextView.setVisibility(View.VISIBLE); captionTextView.setTextColor(0xb2ffffff); } else { captionTextView.setTextColor(0xffffffff); captionTextView.setTag(null); captionTextView.setVisibility(View.INVISIBLE); } } } private void checkProgress(int a, boolean animated) { if (currentFileNames[a] != null) { int index = currentIndex; if (a == 1) { index += 1; } else if (a == 2) { index -= 1; } File f = null; boolean isVideo = false; if (currentMessageObject != null) { MessageObject messageObject = imagesArr.get(index); if (!TextUtils.isEmpty(messageObject.messageOwner.attachPath)) { f = new File(messageObject.messageOwner.attachPath); if (!f.exists()) { f = null; } } if (f == null) { f = FileLoader.getPathToMessage(messageObject.messageOwner); } isVideo = messageObject.isVideo(); } else if (currentBotInlineResult != null) { TLRPC.BotInlineResult botInlineResult = (TLRPC.BotInlineResult) imagesArrLocals.get(index); if (botInlineResult.type.equals("video") || MessageObject.isVideoDocument(botInlineResult.document)) { if (botInlineResult.document != null) { f = FileLoader.getPathToAttach(botInlineResult.document); } else if (botInlineResult.content_url != null) { f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(botInlineResult.content_url) + "." + ImageLoader.getHttpUrlExtension(botInlineResult.content_url, "mp4")); } isVideo = true; } else if (botInlineResult.document != null) { f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), currentFileNames[a]); } else if (botInlineResult.photo != null) { f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_IMAGE), currentFileNames[a]); } if (f == null || !f.exists()) { f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), currentFileNames[a]); } } else if (currentFileLocation != null) { TLRPC.FileLocation location = imagesArrLocations.get(index); f = FileLoader.getPathToAttach(location, avatarsDialogId != 0); } else if (currentPathObject != null) { f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), currentFileNames[a]); if (!f.exists()) { f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), currentFileNames[a]); } } if (f != null && f.exists()) { if (isVideo) { radialProgressViews[a].setBackgroundState(3, animated); } else { radialProgressViews[a].setBackgroundState(-1, animated); } } else { if (isVideo) { if (!FileLoader.getInstance().isLoadingFile(currentFileNames[a])) { radialProgressViews[a].setBackgroundState(2, false); } else { radialProgressViews[a].setBackgroundState(1, false); } } else { radialProgressViews[a].setBackgroundState(0, animated); } Float progress = ImageLoader.getInstance().getFileProgress(currentFileNames[a]); if (progress == null) { progress = 0.0f; } radialProgressViews[a].setProgress(progress, false); } if (a == 0) { canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !isVideo && radialProgressViews[0].backgroundState != 0); } } else { radialProgressViews[a].setBackgroundState(-1, animated); } } private void setIndexToImage(ImageReceiver imageReceiver, int index) { imageReceiver.setOrientation(0, false); if (!imagesArrLocals.isEmpty()) { imageReceiver.setParentMessageObject(null); if (index >= 0 && index < imagesArrLocals.size()) { Object object = imagesArrLocals.get(index); int size = (int) (AndroidUtilities.getPhotoSize() / AndroidUtilities.density); Bitmap placeHolder = null; if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; } if (placeHolder == null) { placeHolder = placeProvider.getThumbForPhoto(null, null, index); } String path = null; TLRPC.Document document = null; TLRPC.FileLocation photo = null; int imageSize = 0; String filter = null; if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; if (!photoEntry.isVideo) { if (photoEntry.imagePath != null) { path = photoEntry.imagePath; } else { imageReceiver.setOrientation(photoEntry.orientation, false); path = photoEntry.path; } filter = String.format(Locale.US, "%d_%d", size, size); } } else if (object instanceof TLRPC.BotInlineResult) { //TODO ? TLRPC.BotInlineResult botInlineResult = ((TLRPC.BotInlineResult) object); if (botInlineResult.type.equals("video") || MessageObject.isVideoDocument(botInlineResult.document)) { if (botInlineResult.document != null) { photo = botInlineResult.document.thumb.location; } else { path = botInlineResult.thumb_url; } } else if (botInlineResult.type.equals("gif") && botInlineResult.document != null) { document = botInlineResult.document; imageSize = botInlineResult.document.size; filter = "d"; } else if (botInlineResult.photo != null) { TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize( botInlineResult.photo.sizes, AndroidUtilities.getPhotoSize()); photo = sizeFull.location; imageSize = sizeFull.size; filter = String.format(Locale.US, "%d_%d", size, size); } else if (botInlineResult.content_url != null) { if (botInlineResult.type.equals("gif")) { filter = "d"; } else { filter = String.format(Locale.US, "%d_%d", size, size); } path = botInlineResult.content_url; } } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage photoEntry = (MediaController.SearchImage) object; if (photoEntry.imagePath != null) { path = photoEntry.imagePath; } else if (photoEntry.document != null) { document = photoEntry.document; imageSize = photoEntry.document.size; } else { path = photoEntry.imageUrl; imageSize = photoEntry.size; } filter = "d"; } if (document != null) { imageReceiver.setImage(document, null, "d", placeHolder != null ? new BitmapDrawable(null, placeHolder) : null, placeHolder == null ? document.thumb.location : null, String.format(Locale.US, "%d_%d", size, size), imageSize, null, false); } else if (photo != null) { imageReceiver.setImage(photo, null, filter, placeHolder != null ? new BitmapDrawable(null, placeHolder) : null, null, String.format(Locale.US, "%d_%d", size, size), imageSize, null, false); } else { imageReceiver.setImage(path, filter, placeHolder != null ? new BitmapDrawable(null, placeHolder) : null, null, imageSize); } } else { imageReceiver.setImageBitmap((Bitmap) null); } } else { int size[] = new int[1]; TLRPC.FileLocation fileLocation = getFileLocation(index, size); if (fileLocation != null) { MessageObject messageObject = null; if (!imagesArr.isEmpty()) { messageObject = imagesArr.get(index); } imageReceiver.setParentMessageObject(messageObject); if (messageObject != null) { imageReceiver.setShouldGenerateQualityThumb(true); } if (messageObject != null && messageObject.isVideo()) { imageReceiver.setNeedsQualityThumb(true); if (messageObject.photoThumbs != null && !messageObject.photoThumbs.isEmpty()) { Bitmap placeHolder = null; if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; } TLRPC.PhotoSize thumbLocation = FileLoader .getClosestPhotoSizeWithSize(messageObject.photoThumbs, 100); imageReceiver.setImage(null, null, null, placeHolder != null ? new BitmapDrawable(null, placeHolder) : null, thumbLocation.location, "b", 0, null, true); } else { imageReceiver.setImageBitmap( parentActivity.getResources().getDrawable(R.drawable.photoview_placeholder)); } } else if (messageObject != null && currentAnimation != null) { imageReceiver.setImageBitmap(currentAnimation); currentAnimation.setSecondParentView(containerView); } else { imageReceiver.setNeedsQualityThumb(false); Bitmap placeHolder = null; if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; } if (size[0] == 0) { size[0] = -1; } TLRPC.PhotoSize thumbLocation = messageObject != null ? FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 100) : null; imageReceiver.setImage(fileLocation, null, null, placeHolder != null ? new BitmapDrawable(null, placeHolder) : null, thumbLocation != null ? thumbLocation.location : null, "b", size[0], null, avatarsDialogId != 0); } } else { imageReceiver.setNeedsQualityThumb(false); imageReceiver.setParentMessageObject(null); if (size[0] == 0) { imageReceiver.setImageBitmap((Bitmap) null); } else { imageReceiver.setImageBitmap( parentActivity.getResources().getDrawable(R.drawable.photoview_placeholder)); } } } } public boolean isShowingImage(MessageObject object) { return isVisible && !disableShowCheck && object != null && currentMessageObject != null && currentMessageObject.getId() == object.getId(); } public boolean isShowingImage(TLRPC.FileLocation object) { return isVisible && !disableShowCheck && object != null && currentFileLocation != null && object.local_id == currentFileLocation.local_id && object.volume_id == currentFileLocation.volume_id && object.dc_id == currentFileLocation.dc_id; } public boolean isShowingImage(String object) { return isVisible && !disableShowCheck && object != null && currentPathObject != null && object.equals(currentPathObject); } public void setParentChatActivity(ChatActivity chatActivity) { parentChatActivity = chatActivity; } public boolean openPhoto(final MessageObject messageObject, long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { return openPhoto(messageObject, null, null, null, 0, provider, null, dialogId, mergeDialogId); } public boolean openPhoto(final TLRPC.FileLocation fileLocation, final PhotoViewerProvider provider) { return openPhoto(null, fileLocation, null, null, 0, provider, null, 0, 0); } public boolean openPhoto(final ArrayList<MessageObject> messages, final int index, long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { return openPhoto(messages.get(index), null, messages, null, index, provider, null, dialogId, mergeDialogId); } public boolean openPhotoForSelect(final ArrayList<Object> photos, final int index, int type, final PhotoViewerProvider provider, ChatActivity chatActivity) { sendPhotoType = type; if (pickerView != null) { pickerView.doneButton .setText(sendPhotoType == 1 ? LocaleController.getString("Set", R.string.Set).toUpperCase() : LocaleController.getString("Send", R.string.Send).toUpperCase()); } return openPhoto(null, null, null, photos, index, provider, chatActivity, 0, 0); } private boolean checkAnimation() { if (animationInProgress != 0) { if (Math.abs(transitionAnimationStartTime - System.currentTimeMillis()) >= 500) { if (animationEndRunnable != null) { animationEndRunnable.run(); animationEndRunnable = null; } animationInProgress = 0; } } return animationInProgress != 0; } public boolean openPhoto(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ArrayList<MessageObject> messages, final ArrayList<Object> photos, final int index, final PhotoViewerProvider provider, ChatActivity chatActivity, long dialogId, long mDialogId) { if (parentActivity == null || isVisible || provider == null && checkAnimation() || messageObject == null && fileLocation == null && messages == null && photos == null) { return false; } final PlaceProviderObject object = provider.getPlaceForPhoto(messageObject, fileLocation, index); if (object == null && photos == null) { return false; } WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); if (attachedToWindow) { try { wm.removeView(windowView); } catch (Exception e) { //don't promt } } try { windowLayoutParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; if (Build.VERSION.SDK_INT >= 21) { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } else { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; } windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; windowView.setFocusable(false); containerView.setFocusable(false); wm.addView(windowView, windowLayoutParams); } catch (Exception e) { FileLog.e("tmessages", e); return false; } parentChatActivity = chatActivity; actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, 1, 1)); NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailedLoad); NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileLoadProgressChanged); NotificationCenter.getInstance().addObserver(this, NotificationCenter.mediaCountDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.mediaDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.dialogPhotosLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.emojiDidLoaded); placeProvider = provider; mergeDialogId = mDialogId; currentDialogId = dialogId; if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } isVisible = true; toggleActionBar(true, false); if (object != null) { disableShowCheck = true; animationInProgress = 1; if (messageObject != null) { currentAnimation = object.imageReceiver.getAnimation(); } onPhotoShow(messageObject, fileLocation, messages, photos, index, object); final Rect drawRegion = object.imageReceiver.getDrawRegion(); int orientation = object.imageReceiver.getOrientation(); int animatedOrientation = object.imageReceiver.getAnimatedOrientation(); if (animatedOrientation != 0) { orientation = animatedOrientation; } animatingImageView.setVisibility(View.VISIBLE); animatingImageView.setRadius(object.radius); animatingImageView.setOrientation(orientation); animatingImageView.setNeedRadius(object.radius != 0); animatingImageView.setImageBitmap(object.thumb); animatingImageView.setAlpha(1.0f); animatingImageView.setPivotX(0.0f); animatingImageView.setPivotY(0.0f); animatingImageView.setScaleX(object.scale); animatingImageView.setScaleY(object.scale); animatingImageView.setTranslationX(object.viewX + drawRegion.left * object.scale); animatingImageView.setTranslationY(object.viewY + drawRegion.top * object.scale); final ViewGroup.LayoutParams layoutParams = animatingImageView.getLayoutParams(); layoutParams.width = (drawRegion.right - drawRegion.left); layoutParams.height = (drawRegion.bottom - drawRegion.top); animatingImageView.setLayoutParams(layoutParams); float scaleX = (float) AndroidUtilities.displaySize.x / layoutParams.width; float scaleY = (float) (AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) / layoutParams.height; float scale = scaleX > scaleY ? scaleY : scaleX; float width = layoutParams.width * scale; float height = layoutParams.height * scale; float xPos = (AndroidUtilities.displaySize.x - width) / 2.0f; float yPos = ((AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) - height) / 2.0f; int clipHorizontal = Math.abs(drawRegion.left - object.imageReceiver.getImageX()); int clipVertical = Math.abs(drawRegion.top - object.imageReceiver.getImageY()); int coords2[] = new int[2]; object.parentView.getLocationInWindow(coords2); int clipTop = coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; if (clipTop < 0) { clipTop = 0; } int clipBottom = (object.viewY + drawRegion.top + layoutParams.height) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; if (clipBottom < 0) { clipBottom = 0; } clipTop = Math.max(clipTop, clipVertical); clipBottom = Math.max(clipBottom, clipVertical); animationValues[0][0] = animatingImageView.getScaleX(); animationValues[0][1] = animatingImageView.getScaleY(); animationValues[0][2] = animatingImageView.getTranslationX(); animationValues[0][3] = animatingImageView.getTranslationY(); animationValues[0][4] = clipHorizontal * object.scale; animationValues[0][5] = clipTop * object.scale; animationValues[0][6] = clipBottom * object.scale; animationValues[0][7] = animatingImageView.getRadius(); animationValues[1][0] = scale; animationValues[1][1] = scale; animationValues[1][2] = xPos; animationValues[1][3] = yPos; animationValues[1][4] = 0; animationValues[1][5] = 0; animationValues[1][6] = 0; animationValues[1][7] = 0; animatingImageView.setAnimationProgress(0); backgroundDrawable.setAlpha(0); containerView.setAlpha(0); final AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(ObjectAnimator.ofFloat(animatingImageView, "animationProgress", 0.0f, 1.0f), ObjectAnimator.ofInt(backgroundDrawable, "alpha", 0, 255), ObjectAnimator.ofFloat(containerView, "alpha", 0.0f, 1.0f)); animationEndRunnable = new Runnable() { @Override public void run() { if (containerView == null || windowView == null) { return; } if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_NONE, null); } animationInProgress = 0; transitionAnimationStartTime = 0; setImages(); containerView.invalidate(); animatingImageView.setVisibility(View.GONE); if (showAfterAnimation != null) { showAfterAnimation.imageReceiver.setVisible(true, true); } if (hideAfterAnimation != null) { hideAfterAnimation.imageReceiver.setVisible(false, true); } if (photos != null && sendPhotoType != 3) { if (Build.VERSION.SDK_INT >= 21) { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } else { windowLayoutParams.flags = 0; } windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); wm.updateViewLayout(windowView, windowLayoutParams); windowView.setFocusable(true); containerView.setFocusable(true); } } }; animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { NotificationCenter.getInstance().setAnimationInProgress(false); if (animationEndRunnable != null) { animationEndRunnable.run(); animationEndRunnable = null; } } }); } }); transitionAnimationStartTime = System.currentTimeMillis(); AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { NotificationCenter.getInstance() .setAllowedNotificationsDutingAnimation(new int[] { NotificationCenter.dialogsNeedReload, NotificationCenter.closeChats, NotificationCenter.mediaCountDidLoaded, NotificationCenter.mediaDidLoaded, NotificationCenter.dialogPhotosLoaded }); NotificationCenter.getInstance().setAnimationInProgress(true); animatorSet.start(); } }); if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } backgroundDrawable.drawRunnable = new Runnable() { @Override public void run() { disableShowCheck = false; object.imageReceiver.setVisible(false, true); } }; } else { if (photos != null && sendPhotoType != 3) { if (Build.VERSION.SDK_INT >= 21) { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } else { windowLayoutParams.flags = 0; } windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; wm.updateViewLayout(windowView, windowLayoutParams); windowView.setFocusable(true); containerView.setFocusable(true); } backgroundDrawable.setAlpha(255); containerView.setAlpha(1.0f); onPhotoShow(messageObject, fileLocation, messages, photos, index, object); } return true; } public void closePhoto(boolean animated, boolean fromEditMode) { if (!fromEditMode && currentEditMode != 0) { if (currentEditMode == 3 && photoPaintView != null) { photoPaintView.maybeShowDismissalAlert(this, parentActivity, new Runnable() { @Override public void run() { switchToEditMode(0); } }); return; } if (currentEditMode == 1) { photoCropView.cancelAnimationRunnable(); } switchToEditMode(0); return; } try { if (visibleDialog != null) { visibleDialog.dismiss(); visibleDialog = null; } } catch (Exception e) { FileLog.e("tmessages", e); } if (currentEditMode != 0) { if (currentEditMode == 2) { photoFilterView.shutdown(); containerView.removeView(photoFilterView); photoFilterView = null; } else if (currentEditMode == 1) { editorDoneLayout.setVisibility(View.GONE); photoCropView.setVisibility(View.GONE); } currentEditMode = 0; } if (parentActivity == null || !isVisible || checkAnimation() || placeProvider == null) { return; } if (captionEditText.hideActionMode() && !fromEditMode) { return; } releasePlayer(); captionEditText.onDestroy(); parentChatActivity = null; NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileDidFailedLoad); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileLoadProgressChanged); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.mediaCountDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.mediaDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.dialogPhotosLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.emojiDidLoaded); ConnectionsManager.getInstance().cancelRequestsForGuid(classGuid); isActionBarVisible = false; if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } ConnectionsManager.getInstance().cancelRequestsForGuid(classGuid); final PlaceProviderObject object = placeProvider.getPlaceForPhoto(currentMessageObject, currentFileLocation, currentIndex); if (animated) { animationInProgress = 1; animatingImageView.setVisibility(View.VISIBLE); containerView.invalidate(); AnimatorSet animatorSet = new AnimatorSet(); final ViewGroup.LayoutParams layoutParams = animatingImageView.getLayoutParams(); Rect drawRegion = null; int orientation = centerImage.getOrientation(); int animatedOrientation = 0; if (object != null && object.imageReceiver != null) { animatedOrientation = object.imageReceiver.getAnimatedOrientation(); } if (animatedOrientation != 0) { orientation = animatedOrientation; } animatingImageView.setOrientation(orientation); if (object != null) { animatingImageView.setNeedRadius(object.radius != 0); drawRegion = object.imageReceiver.getDrawRegion(); layoutParams.width = drawRegion.right - drawRegion.left; layoutParams.height = drawRegion.bottom - drawRegion.top; animatingImageView.setImageBitmap(object.thumb); } else { animatingImageView.setNeedRadius(false); layoutParams.width = centerImage.getImageWidth(); layoutParams.height = centerImage.getImageHeight(); animatingImageView.setImageBitmap(centerImage.getBitmap()); } animatingImageView.setLayoutParams(layoutParams); float scaleX = (float) AndroidUtilities.displaySize.x / layoutParams.width; float scaleY = (float) (AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) / layoutParams.height; float scale2 = scaleX > scaleY ? scaleY : scaleX; float width = layoutParams.width * scale * scale2; float height = layoutParams.height * scale * scale2; float xPos = (AndroidUtilities.displaySize.x - width) / 2.0f; float yPos = ((AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) - height) / 2.0f; animatingImageView.setTranslationX(xPos + translationX); animatingImageView.setTranslationY(yPos + translationY); animatingImageView.setScaleX(scale * scale2); animatingImageView.setScaleY(scale * scale2); if (object != null) { object.imageReceiver.setVisible(false, true); int clipHorizontal = Math.abs(drawRegion.left - object.imageReceiver.getImageX()); int clipVertical = Math.abs(drawRegion.top - object.imageReceiver.getImageY()); int coords2[] = new int[2]; object.parentView.getLocationInWindow(coords2); int clipTop = coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition; if (clipTop < 0) { clipTop = 0; } int clipBottom = (object.viewY + drawRegion.top + (drawRegion.bottom - drawRegion.top)) - (coords2[1] + object.parentView.getHeight() - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight)) + object.clipBottomAddition; if (clipBottom < 0) { clipBottom = 0; } clipTop = Math.max(clipTop, clipVertical); clipBottom = Math.max(clipBottom, clipVertical); animationValues[0][0] = animatingImageView.getScaleX(); animationValues[0][1] = animatingImageView.getScaleY(); animationValues[0][2] = animatingImageView.getTranslationX(); animationValues[0][3] = animatingImageView.getTranslationY(); animationValues[0][4] = 0; animationValues[0][5] = 0; animationValues[0][6] = 0; animationValues[0][7] = 0; animationValues[1][0] = object.scale; animationValues[1][1] = object.scale; animationValues[1][2] = object.viewX + drawRegion.left * object.scale; animationValues[1][3] = object.viewY + drawRegion.top * object.scale; animationValues[1][4] = clipHorizontal * object.scale; animationValues[1][5] = clipTop * object.scale; animationValues[1][6] = clipBottom * object.scale; animationValues[1][7] = object.radius; animatorSet.playTogether( ObjectAnimator.ofFloat(animatingImageView, "animationProgress", 0.0f, 1.0f), ObjectAnimator.ofInt(backgroundDrawable, "alpha", 0), ObjectAnimator.ofFloat(containerView, "alpha", 0.0f)); } else { int h = (AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)); animatorSet.playTogether(ObjectAnimator.ofInt(backgroundDrawable, "alpha", 0), ObjectAnimator.ofFloat(animatingImageView, "alpha", 0.0f), ObjectAnimator.ofFloat(animatingImageView, "translationY", translationY >= 0 ? h : -h), ObjectAnimator.ofFloat(containerView, "alpha", 0.0f)); } animationEndRunnable = new Runnable() { @Override public void run() { if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_NONE, null); } animationInProgress = 0; onPhotoClosed(object); } }; animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { if (animationEndRunnable != null) { animationEndRunnable.run(); animationEndRunnable = null; } } }); } }); transitionAnimationStartTime = System.currentTimeMillis(); if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } animatorSet.start(); } else { AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(ObjectAnimator.ofFloat(containerView, "scaleX", 0.9f), ObjectAnimator.ofFloat(containerView, "scaleY", 0.9f), ObjectAnimator.ofInt(backgroundDrawable, "alpha", 0), ObjectAnimator.ofFloat(containerView, "alpha", 0.0f)); animationInProgress = 2; animationEndRunnable = new Runnable() { @Override public void run() { if (containerView == null) { return; } if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_NONE, null); } animationInProgress = 0; onPhotoClosed(object); containerView.setScaleX(1.0f); containerView.setScaleY(1.0f); } }; animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { if (animationEndRunnable != null) { animationEndRunnable.run(); animationEndRunnable = null; } } }); transitionAnimationStartTime = System.currentTimeMillis(); if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } animatorSet.start(); } if (currentAnimation != null) { currentAnimation.setSecondParentView(null); currentAnimation = null; centerImage.setImageBitmap((Drawable) null); } if (placeProvider instanceof EmptyPhotoViewerProvider) { placeProvider.cancelButtonPressed(); } } public void destroyPhotoViewer() { if (parentActivity == null || windowView == null) { return; } releasePlayer(); try { if (windowView.getParent() != null) { WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); wm.removeViewImmediate(windowView); } windowView = null; } catch (Exception e) { FileLog.e("tmessages", e); } if (captionEditText != null) { captionEditText.onDestroy(); } Instance = null; } private void onPhotoClosed(PlaceProviderObject object) { isVisible = false; disableShowCheck = true; currentMessageObject = null; currentBotInlineResult = null; currentFileLocation = null; currentPathObject = null; currentThumb = null; if (currentAnimation != null) { currentAnimation.setSecondParentView(null); currentAnimation = null; } for (int a = 0; a < 3; a++) { if (radialProgressViews[a] != null) { radialProgressViews[a].setBackgroundState(-1, false); } } centerImage.setImageBitmap((Bitmap) null); leftImage.setImageBitmap((Bitmap) null); rightImage.setImageBitmap((Bitmap) null); containerView.post(new Runnable() { @Override public void run() { animatingImageView.setImageBitmap(null); try { if (windowView.getParent() != null) { WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); wm.removeView(windowView); } } catch (Exception e) { FileLog.e("tmessages", e); } } }); if (placeProvider != null) { placeProvider.willHidePhotoViewer(); } placeProvider = null; disableShowCheck = false; if (object != null) { object.imageReceiver.setVisible(true, true); } } private void redraw(final int count) { if (count < 6) { if (containerView != null) { containerView.invalidate(); AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { redraw(count + 1); } }, 100); } } } public void onResume() { redraw(0); //workaround for camera bug } public void onPause() { if (currentAnimation != null) { closePhoto(false, false); return; } if (captionDoneItem.getVisibility() != View.GONE) { closeCaptionEnter(true); } } public boolean isVisible() { return isVisible && placeProvider != null; } private void updateMinMax(float scale) { int maxW = (int) (centerImage.getImageWidth() * scale - getContainerViewWidth()) / 2; int maxH = (int) (centerImage.getImageHeight() * scale - getContainerViewHeight()) / 2; if (maxW > 0) { minX = -maxW; maxX = maxW; } else { minX = maxX = 0; } if (maxH > 0) { minY = -maxH; maxY = maxH; } else { minY = maxY = 0; } if (currentEditMode == 1) { maxX += photoCropView.getLimitX(); maxY += photoCropView.getLimitY(); minX -= photoCropView.getLimitWidth(); minY -= photoCropView.getLimitHeight(); } } private int getAdditionX() { if (currentEditMode != 0 && currentEditMode != 3) { return AndroidUtilities.dp(14); } return 0; } private int getAdditionY() { if (currentEditMode == 3) { return ActionBar.getCurrentActionBarHeight() + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); } else if (currentEditMode != 0) { return AndroidUtilities.dp(14) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); } return 0; } private int getContainerViewWidth() { return getContainerViewWidth(currentEditMode); } private int getContainerViewWidth(int mode) { int width = containerView.getWidth(); if (mode != 0 && mode != 3) { width -= AndroidUtilities.dp(28); } return width; } private int getContainerViewHeight() { return getContainerViewHeight(currentEditMode); } private int getContainerViewHeight(int mode) { int height = AndroidUtilities.displaySize.y; if (mode == 0 && Build.VERSION.SDK_INT >= 21) { height += AndroidUtilities.statusBarHeight; } if (mode == 1) { height -= AndroidUtilities.dp(76); } else if (mode == 2) { height -= AndroidUtilities.dp(154); } else if (mode == 3) { height -= AndroidUtilities.dp(48) + ActionBar.getCurrentActionBarHeight(); } return height; } private boolean onTouchEvent(MotionEvent ev) { if (animationInProgress != 0 || animationStartTime != 0) { return false; } if (currentEditMode == 2) { photoFilterView.onTouch(ev); return true; } if (currentEditMode == 1) { if (ev.getPointerCount() == 1) { if (photoCropView.onTouch(ev)) { updateMinMax(scale); return true; } } else { photoCropView.onTouch(null); } } if (captionEditText.isPopupShowing() || captionEditText.isKeyboardVisible()) { if (ev.getAction() == MotionEvent.ACTION_UP) { closeCaptionEnter(true); } return true; } if (currentEditMode == 0 && ev.getPointerCount() == 1 && gestureDetector.onTouchEvent(ev)) { if (doubleTap) { doubleTap = false; moving = false; zooming = false; checkMinMax(false); return true; } } if (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { if (currentEditMode == 1) { photoCropView.cancelAnimationRunnable(); } discardTap = false; if (!scroller.isFinished()) { scroller.abortAnimation(); } if (!draggingDown && !changingPage) { if (canZoom && ev.getPointerCount() == 2) { pinchStartDistance = (float) Math.hypot(ev.getX(1) - ev.getX(0), ev.getY(1) - ev.getY(0)); pinchStartScale = scale; pinchCenterX = (ev.getX(0) + ev.getX(1)) / 2.0f; pinchCenterY = (ev.getY(0) + ev.getY(1)) / 2.0f; pinchStartX = translationX; pinchStartY = translationY; zooming = true; moving = false; if (velocityTracker != null) { velocityTracker.clear(); } } else if (ev.getPointerCount() == 1) { moveStartX = ev.getX(); dragY = moveStartY = ev.getY(); draggingDown = false; canDragDown = true; if (velocityTracker != null) { velocityTracker.clear(); } } } } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) { if (currentEditMode == 1) { photoCropView.cancelAnimationRunnable(); } if (canZoom && ev.getPointerCount() == 2 && !draggingDown && zooming && !changingPage) { discardTap = true; scale = (float) Math.hypot(ev.getX(1) - ev.getX(0), ev.getY(1) - ev.getY(0)) / pinchStartDistance * pinchStartScale; translationX = (pinchCenterX - getContainerViewWidth() / 2) - ((pinchCenterX - getContainerViewWidth() / 2) - pinchStartX) * (scale / pinchStartScale); translationY = (pinchCenterY - getContainerViewHeight() / 2) - ((pinchCenterY - getContainerViewHeight() / 2) - pinchStartY) * (scale / pinchStartScale); updateMinMax(scale); containerView.invalidate(); } else if (ev.getPointerCount() == 1) { if (velocityTracker != null) { velocityTracker.addMovement(ev); } float dx = Math.abs(ev.getX() - moveStartX); float dy = Math.abs(ev.getY() - dragY); if (dx > AndroidUtilities.dp(3) || dy > AndroidUtilities.dp(3)) { discardTap = true; } if (!(placeProvider instanceof EmptyPhotoViewerProvider) && currentEditMode == 0 && canDragDown && !draggingDown && scale == 1 && dy >= AndroidUtilities.dp(30) && dy / 2 > dx) { draggingDown = true; moving = false; dragY = ev.getY(); if (isActionBarVisible && canShowBottom) { toggleActionBar(false, true); } else if (pickerView.getVisibility() == View.VISIBLE) { toggleActionBar(false, true); toggleCheckImageView(false); } return true; } else if (draggingDown) { translationY = ev.getY() - dragY; containerView.invalidate(); } else if (!invalidCoords && animationStartTime == 0) { float moveDx = moveStartX - ev.getX(); float moveDy = moveStartY - ev.getY(); if (moving || currentEditMode != 0 || scale == 1 && Math.abs(moveDy) + AndroidUtilities.dp(12) < Math.abs(moveDx) || scale != 1) { if (!moving) { moveDx = 0; moveDy = 0; moving = true; canDragDown = false; } moveStartX = ev.getX(); moveStartY = ev.getY(); updateMinMax(scale); if (translationX < minX && (currentEditMode != 0 || !rightImage.hasImage()) || translationX > maxX && (currentEditMode != 0 || !leftImage.hasImage())) { moveDx /= 3.0f; } if (maxY == 0 && minY == 0 && currentEditMode == 0) { if (translationY - moveDy < minY) { translationY = minY; moveDy = 0; } else if (translationY - moveDy > maxY) { translationY = maxY; moveDy = 0; } } else { if (translationY < minY || translationY > maxY) { moveDy /= 3.0f; } } translationX -= moveDx; if (scale != 1 || currentEditMode != 0) { translationY -= moveDy; } containerView.invalidate(); } } else { invalidCoords = false; moveStartX = ev.getX(); moveStartY = ev.getY(); } } } else if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL || ev.getActionMasked() == MotionEvent.ACTION_UP || ev.getActionMasked() == MotionEvent.ACTION_POINTER_UP) { if (currentEditMode == 1) { photoCropView.startAnimationRunnable(); } if (zooming) { invalidCoords = true; if (scale < 1.0f) { updateMinMax(1.0f); animateTo(1.0f, 0, 0, true); } else if (scale > 3.0f) { float atx = (pinchCenterX - getContainerViewWidth() / 2) - ((pinchCenterX - getContainerViewWidth() / 2) - pinchStartX) * (3.0f / pinchStartScale); float aty = (pinchCenterY - getContainerViewHeight() / 2) - ((pinchCenterY - getContainerViewHeight() / 2) - pinchStartY) * (3.0f / pinchStartScale); updateMinMax(3.0f); if (atx < minX) { atx = minX; } else if (atx > maxX) { atx = maxX; } if (aty < minY) { aty = minY; } else if (aty > maxY) { aty = maxY; } animateTo(3.0f, atx, aty, true); } else { checkMinMax(true); } zooming = false; } else if (draggingDown) { if (Math.abs(dragY - ev.getY()) > getContainerViewHeight() / 6.0f) { closePhoto(true, false); } else { if (pickerView.getVisibility() == View.VISIBLE) { toggleActionBar(true, true); toggleCheckImageView(true); } animateTo(1, 0, 0, false); } draggingDown = false; } else if (moving) { float moveToX = translationX; float moveToY = translationY; updateMinMax(scale); moving = false; canDragDown = true; float velocity = 0; if (velocityTracker != null && scale == 1) { velocityTracker.computeCurrentVelocity(1000); velocity = velocityTracker.getXVelocity(); } if (currentEditMode == 0) { if ((translationX < minX - getContainerViewWidth() / 3 || velocity < -AndroidUtilities.dp(650)) && rightImage.hasImage()) { goToNext(); return true; } if ((translationX > maxX + getContainerViewWidth() / 3 || velocity > AndroidUtilities.dp(650)) && leftImage.hasImage()) { goToPrev(); return true; } } if (translationX < minX) { moveToX = minX; } else if (translationX > maxX) { moveToX = maxX; } if (translationY < minY) { moveToY = minY; } else if (translationY > maxY) { moveToY = maxY; } animateTo(scale, moveToX, moveToY, false); } } return false; } private void checkMinMax(boolean zoom) { float moveToX = translationX; float moveToY = translationY; updateMinMax(scale); if (translationX < minX) { moveToX = minX; } else if (translationX > maxX) { moveToX = maxX; } if (translationY < minY) { moveToY = minY; } else if (translationY > maxY) { moveToY = maxY; } animateTo(scale, moveToX, moveToY, zoom); } private void goToNext() { float extra = 0; if (scale != 1) { extra = (getContainerViewWidth() - centerImage.getImageWidth()) / 2 * scale; } switchImageAfterAnimation = 1; animateTo(scale, minX - getContainerViewWidth() - extra - AndroidUtilities.dp(30) / 2, translationY, false); } private void goToPrev() { float extra = 0; if (scale != 1) { extra = (getContainerViewWidth() - centerImage.getImageWidth()) / 2 * scale; } switchImageAfterAnimation = 2; animateTo(scale, maxX + getContainerViewWidth() + extra + AndroidUtilities.dp(30) / 2, translationY, false); } private void animateTo(float newScale, float newTx, float newTy, boolean isZoom) { animateTo(newScale, newTx, newTy, isZoom, 250); } private void animateTo(float newScale, float newTx, float newTy, boolean isZoom, int duration) { if (scale == newScale && translationX == newTx && translationY == newTy) { return; } zoomAnimation = isZoom; animateToScale = newScale; animateToX = newTx; animateToY = newTy; animationStartTime = System.currentTimeMillis(); imageMoveAnimation = new AnimatorSet(); imageMoveAnimation.playTogether(ObjectAnimator.ofFloat(this, "animationValue", 0, 1)); imageMoveAnimation.setInterpolator(interpolator); imageMoveAnimation.setDuration(duration); imageMoveAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Animator animation) { imageMoveAnimation = null; containerView.invalidate(); } }); imageMoveAnimation.start(); } public void setAnimationValue(float value) { animationValue = value; containerView.invalidate(); } public float getAnimationValue() { return animationValue; } @SuppressLint("NewApi") private void onDraw(Canvas canvas) { if (animationInProgress == 1 || !isVisible && animationInProgress != 2) { return; } float currentTranslationY; float currentTranslationX; float currentScale; float aty = -1; if (imageMoveAnimation != null) { if (!scroller.isFinished()) { scroller.abortAnimation(); } float ts = scale + (animateToScale - scale) * animationValue; float tx = translationX + (animateToX - translationX) * animationValue; float ty = translationY + (animateToY - translationY) * animationValue; if (currentEditMode == 1) { photoCropView.setAnimationProgress(animationValue); } if (animateToScale == 1 && scale == 1 && translationX == 0) { aty = ty; } currentScale = ts; currentTranslationY = ty; currentTranslationX = tx; containerView.invalidate(); } else { if (animationStartTime != 0) { translationX = animateToX; translationY = animateToY; scale = animateToScale; animationStartTime = 0; if (currentEditMode == 1) { photoCropView.setAnimationProgress(1); } updateMinMax(scale); zoomAnimation = false; } if (!scroller.isFinished()) { if (scroller.computeScrollOffset()) { if (scroller.getStartX() < maxX && scroller.getStartX() > minX) { translationX = scroller.getCurrX(); } if (scroller.getStartY() < maxY && scroller.getStartY() > minY) { translationY = scroller.getCurrY(); } containerView.invalidate(); } } if (switchImageAfterAnimation != 0) { if (switchImageAfterAnimation == 1) { setImageIndex(currentIndex + 1, false); } else if (switchImageAfterAnimation == 2) { setImageIndex(currentIndex - 1, false); } switchImageAfterAnimation = 0; } currentScale = scale; currentTranslationY = translationY; currentTranslationX = translationX; if (!moving) { aty = translationY; } } if (currentEditMode == 0 && scale == 1 && aty != -1 && !zoomAnimation) { float maxValue = getContainerViewHeight() / 4.0f; backgroundDrawable .setAlpha((int) Math.max(127, 255 * (1.0f - (Math.min(Math.abs(aty), maxValue) / maxValue)))); } else { backgroundDrawable.setAlpha(255); } ImageReceiver sideImage = null; if (currentEditMode == 0) { if (scale >= 1.0f && !zoomAnimation && !zooming) { if (currentTranslationX > maxX + AndroidUtilities.dp(5)) { sideImage = leftImage; } else if (currentTranslationX < minX - AndroidUtilities.dp(5)) { sideImage = rightImage; } } changingPage = sideImage != null; } if (sideImage == rightImage) { float tranlateX = currentTranslationX; float scaleDiff = 0; float alpha = 1; if (!zoomAnimation && tranlateX < minX) { alpha = Math.min(1.0f, (minX - tranlateX) / canvas.getWidth()); scaleDiff = (1.0f - alpha) * 0.3f; tranlateX = -canvas.getWidth() - AndroidUtilities.dp(30) / 2; } if (sideImage.hasBitmapImage()) { canvas.save(); canvas.translate(getContainerViewWidth() / 2, getContainerViewHeight() / 2); canvas.translate(canvas.getWidth() + AndroidUtilities.dp(30) / 2 + tranlateX, 0); canvas.scale(1.0f - scaleDiff, 1.0f - scaleDiff); int bitmapWidth = sideImage.getBitmapWidth(); int bitmapHeight = sideImage.getBitmapHeight(); float scaleX = (float) getContainerViewWidth() / (float) bitmapWidth; float scaleY = (float) getContainerViewHeight() / (float) bitmapHeight; float scale = scaleX > scaleY ? scaleY : scaleX; int width = (int) (bitmapWidth * scale); int height = (int) (bitmapHeight * scale); sideImage.setAlpha(alpha); sideImage.setImageCoords(-width / 2, -height / 2, width, height); sideImage.draw(canvas); canvas.restore(); } canvas.save(); canvas.translate(tranlateX, currentTranslationY / currentScale); canvas.translate((canvas.getWidth() * (scale + 1) + AndroidUtilities.dp(30)) / 2, -currentTranslationY / currentScale); radialProgressViews[1].setScale(1.0f - scaleDiff); radialProgressViews[1].setAlpha(alpha); radialProgressViews[1].onDraw(canvas); canvas.restore(); } float translateX = currentTranslationX; float scaleDiff = 0; float alpha = 1; if (!zoomAnimation && translateX > maxX && currentEditMode == 0) { alpha = Math.min(1.0f, (translateX - maxX) / canvas.getWidth()); scaleDiff = alpha * 0.3f; alpha = 1.0f - alpha; translateX = maxX; } boolean drawTextureView = Build.VERSION.SDK_INT >= 16 && aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == View.VISIBLE; if (centerImage.hasBitmapImage()) { canvas.save(); canvas.translate(getContainerViewWidth() / 2 + getAdditionX(), getContainerViewHeight() / 2 + getAdditionY()); canvas.translate(translateX, currentTranslationY); canvas.scale(currentScale - scaleDiff, currentScale - scaleDiff); if (currentEditMode == 1) { photoCropView.setBitmapParams(currentScale, translateX, currentTranslationY); } int bitmapWidth = centerImage.getBitmapWidth(); int bitmapHeight = centerImage.getBitmapHeight(); if (drawTextureView && textureUploaded) { float scale1 = bitmapWidth / (float) bitmapHeight; float scale2 = videoTextureView.getMeasuredWidth() / (float) videoTextureView.getMeasuredHeight(); if (Math.abs(scale1 - scale2) > 0.01f) { bitmapWidth = videoTextureView.getMeasuredWidth(); bitmapHeight = videoTextureView.getMeasuredHeight(); } } float scaleX = (float) getContainerViewWidth() / (float) bitmapWidth; float scaleY = (float) getContainerViewHeight() / (float) bitmapHeight; float scale = scaleX > scaleY ? scaleY : scaleX; int width = (int) (bitmapWidth * scale); int height = (int) (bitmapHeight * scale); if (!drawTextureView || !textureUploaded || !videoCrossfadeStarted || videoCrossfadeAlpha != 1.0f) { centerImage.setAlpha(alpha); centerImage.setImageCoords(-width / 2, -height / 2, width, height); centerImage.draw(canvas); } if (drawTextureView) { if (!videoCrossfadeStarted && textureUploaded) { videoCrossfadeStarted = true; videoCrossfadeAlpha = 0.0f; videoCrossfadeAlphaLastTime = System.currentTimeMillis(); } canvas.translate(-width / 2, -height / 2); videoTextureView.setAlpha(alpha * videoCrossfadeAlpha); aspectRatioFrameLayout.draw(canvas); if (videoCrossfadeStarted && videoCrossfadeAlpha < 1.0f) { long newUpdateTime = System.currentTimeMillis(); long dt = newUpdateTime - videoCrossfadeAlphaLastTime; videoCrossfadeAlphaLastTime = newUpdateTime; videoCrossfadeAlpha += dt / 300.0f; containerView.invalidate(); if (videoCrossfadeAlpha > 1.0f) { videoCrossfadeAlpha = 1.0f; } } } canvas.restore(); } if (!drawTextureView && (videoPlayerControlFrameLayout == null || videoPlayerControlFrameLayout.getVisibility() != View.VISIBLE)) { canvas.save(); canvas.translate(translateX, currentTranslationY / currentScale); radialProgressViews[0].setScale(1.0f - scaleDiff); radialProgressViews[0].setAlpha(alpha); radialProgressViews[0].onDraw(canvas); canvas.restore(); } if (sideImage == leftImage) { if (sideImage.hasBitmapImage()) { canvas.save(); canvas.translate(getContainerViewWidth() / 2, getContainerViewHeight() / 2); canvas.translate( -(canvas.getWidth() * (scale + 1) + AndroidUtilities.dp(30)) / 2 + currentTranslationX, 0); int bitmapWidth = sideImage.getBitmapWidth(); int bitmapHeight = sideImage.getBitmapHeight(); float scaleX = (float) getContainerViewWidth() / (float) bitmapWidth; float scaleY = (float) getContainerViewHeight() / (float) bitmapHeight; float scale = scaleX > scaleY ? scaleY : scaleX; int width = (int) (bitmapWidth * scale); int height = (int) (bitmapHeight * scale); sideImage.setAlpha(1.0f); sideImage.setImageCoords(-width / 2, -height / 2, width, height); sideImage.draw(canvas); canvas.restore(); } canvas.save(); canvas.translate(currentTranslationX, currentTranslationY / currentScale); canvas.translate(-(canvas.getWidth() * (scale + 1) + AndroidUtilities.dp(30)) / 2, -currentTranslationY / currentScale); radialProgressViews[2].setScale(1.0f); radialProgressViews[2].setAlpha(1.0f); radialProgressViews[2].onDraw(canvas); canvas.restore(); } } private void onActionClick(boolean download) { if (currentMessageObject == null && currentBotInlineResult == null || currentFileNames[0] == null) { return; } File file = null; if (currentMessageObject != null) { if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() != 0) { file = new File(currentMessageObject.messageOwner.attachPath); if (!file.exists()) { file = null; } } if (file == null) { file = FileLoader.getPathToMessage(currentMessageObject.messageOwner); if (!file.exists()) { file = null; } } } else if (currentBotInlineResult != null) { if (currentBotInlineResult.document != null) { file = FileLoader.getPathToAttach(currentBotInlineResult.document); if (!file.exists()) { file = null; } } else { file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(currentBotInlineResult.content_url) + "." + ImageLoader.getHttpUrlExtension(currentBotInlineResult.content_url, "mp4")); if (!file.exists()) { file = null; } } } if (file == null) { if (download) { if (currentMessageObject != null) { if (!FileLoader.getInstance().isLoadingFile(currentFileNames[0])) { FileLoader.getInstance().loadFile(currentMessageObject.getDocument(), true, false); } else { FileLoader.getInstance().cancelLoadFile(currentMessageObject.getDocument()); } } else if (currentBotInlineResult != null) { if (currentBotInlineResult.document != null) { if (!FileLoader.getInstance().isLoadingFile(currentFileNames[0])) { FileLoader.getInstance().loadFile(currentBotInlineResult.document, true, false); } else { FileLoader.getInstance().cancelLoadFile(currentBotInlineResult.document); } } else { if (!ImageLoader.getInstance().isLoadingHttpFile(currentBotInlineResult.content_url)) { ImageLoader.getInstance().loadHttpFile(currentBotInlineResult.content_url, "mp4"); } else { ImageLoader.getInstance().cancelLoadHttpFile(currentBotInlineResult.content_url); } } } } } else { if (Build.VERSION.SDK_INT >= 16) { preparePlayer(file, true); } else { Intent intent = new Intent(Intent.ACTION_VIEW); if (Build.VERSION.SDK_INT >= 24) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(FileProvider.getUriForFile(parentActivity, BuildConfig.APPLICATION_ID + ".provider", file), "video/mp4"); } else { intent.setDataAndType(Uri.fromFile(file), "video/mp4"); } parentActivity.startActivityForResult(intent, 500); } } } @Override public boolean onDown(MotionEvent e) { return false; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (scale != 1) { scroller.abortAnimation(); scroller.fling(Math.round(translationX), Math.round(translationY), Math.round(velocityX), Math.round(velocityY), (int) minX, (int) maxX, (int) minY, (int) maxY); containerView.postInvalidate(); } return false; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { if (discardTap) { return false; } if (canShowBottom) { boolean drawTextureView = Build.VERSION.SDK_INT >= 16 && aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == View.VISIBLE; if (radialProgressViews[0] != null && containerView != null && !drawTextureView) { int state = radialProgressViews[0].backgroundState; if (state > 0 && state <= 3) { float x = e.getX(); float y = e.getY(); if (x >= (getContainerViewWidth() - AndroidUtilities.dp(100)) / 2.0f && x <= (getContainerViewWidth() + AndroidUtilities.dp(100)) / 2.0f && y >= (getContainerViewHeight() - AndroidUtilities.dp(100)) / 2.0f && y <= (getContainerViewHeight() + AndroidUtilities.dp(100)) / 2.0f) { onActionClick(true); checkProgress(0, true); return true; } } } toggleActionBar(!isActionBarVisible, true); } else if (sendPhotoType == 0) { checkImageView.performClick(); } else if (currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document))) { int state = radialProgressViews[0].backgroundState; if (state > 0 && state <= 3) { float x = e.getX(); float y = e.getY(); if (x >= (getContainerViewWidth() - AndroidUtilities.dp(100)) / 2.0f && x <= (getContainerViewWidth() + AndroidUtilities.dp(100)) / 2.0f && y >= (getContainerViewHeight() - AndroidUtilities.dp(100)) / 2.0f && y <= (getContainerViewHeight() + AndroidUtilities.dp(100)) / 2.0f) { onActionClick(true); checkProgress(0, true); return true; } } } return true; } @Override public boolean onDoubleTap(MotionEvent e) { if (!canZoom || scale == 1.0f && (translationY != 0 || translationX != 0)) { return false; } if (animationStartTime != 0 || animationInProgress != 0) { return false; } if (scale == 1.0f) { float atx = (e.getX() - getContainerViewWidth() / 2) - ((e.getX() - getContainerViewWidth() / 2) - translationX) * (3.0f / scale); float aty = (e.getY() - getContainerViewHeight() / 2) - ((e.getY() - getContainerViewHeight() / 2) - translationY) * (3.0f / scale); updateMinMax(3.0f); if (atx < minX) { atx = minX; } else if (atx > maxX) { atx = maxX; } if (aty < minY) { aty = minY; } else if (aty > maxY) { aty = maxY; } animateTo(3.0f, atx, aty, true); } else { animateTo(1.0f, 0, 0, true); } doubleTap = true; return true; } @Override public boolean onDoubleTapEvent(MotionEvent e) { return false; } }