/* * This is the source code of Telegram for Android v. 5.x.x. * It is licensed under GNU GPL v. 2 or later. * You should have received a copy of the license in this archive (see LICENSE). * * Copyright Nikolai Kudashov, 2013-2018. */ package org.telegram.ui; import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; 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.graphics.drawable.GradientDrawable; import android.media.MediaCodecInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.provider.Settings; import android.text.Layout; import android.text.Selection; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.text.method.Touch; import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.transition.ChangeBounds; import android.transition.Fade; import android.transition.Transition; import android.transition.TransitionManager; import android.transition.TransitionSet; import android.transition.TransitionValues; import android.util.FloatProperty; import android.util.Property; import android.util.SparseArray; import android.util.TypedValue; import android.view.ActionMode; import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.Menu; import android.view.MotionEvent; import android.view.Surface; import android.view.TextureView; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import android.view.animation.OvershootInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.OverScroller; import android.widget.Scroller; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.collection.ArrayMap; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.core.view.ViewCompat; import androidx.core.widget.NestedScrollView; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScrollerEnd; import androidx.recyclerview.widget.RecyclerView; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import org.jetbrains.annotations.NotNull; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Bitmaps; import org.telegram.messenger.BringAppForegroundService; import org.telegram.messenger.BuildConfig; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DownloadController; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SecureDocument; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; import org.telegram.messenger.WebFile; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.MentionsAdapter; import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.PhotoPickerPhotoCell; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.CheckBox; import org.telegram.ui.Components.ClippingImageView; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.FadingTextViewLayout; import org.telegram.ui.Components.FilterShaders; import org.telegram.ui.Components.GestureDetector2; import org.telegram.ui.Components.GroupedPhotosListView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.NumberPicker; import org.telegram.ui.Components.OtherDocumentPlaceholderDrawable; import org.telegram.ui.Components.PaintingOverlay; 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.PipVideoView; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SizeNotifierFrameLayoutPhoto; import org.telegram.ui.Components.StickersAlert; import org.telegram.ui.Components.TextViewSwitcher; import org.telegram.ui.Components.Tooltip; import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.URLSpanUserMentionPhotoViewer; import org.telegram.ui.Components.VideoEditTextureView; import org.telegram.ui.Components.VideoForwardDrawable; import org.telegram.ui.Components.VideoPlayer; import org.telegram.ui.Components.VideoPlayerSeekBar; import org.telegram.ui.Components.VideoSeekPreviewImage; import org.telegram.ui.Components.VideoTimelinePlayView; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import kotlin.Unit; import tw.nekomimi.nekogram.NekoConfig; import tw.nekomimi.nekogram.NekoXConfig; import tw.nekomimi.nekogram.transtale.TranslateDb; import tw.nekomimi.nekogram.transtale.Translator; import tw.nekomimi.nekogram.transtale.TranslatorKt; import tw.nekomimi.nekogram.utils.AlertUtil; import tw.nekomimi.nekogram.utils.ProxyUtil; @SuppressWarnings("unchecked") public class PhotoViewer implements NotificationCenter.NotificationCenterDelegate, GestureDetector2.OnGestureListener, GestureDetector2.OnDoubleTapListener { private int classGuid; private PhotoViewerProvider placeProvider; private boolean isVisible; private int maxSelectedPhotos = -1; private boolean allowOrder = true; private boolean muteVideo; private int slideshowMessageId; private String nameOverride; private int dateOverride; private AnimatorSet miniProgressAnimator; private Runnable miniProgressShowRunnable = () -> toggleMiniProgressInternal(true); private Activity parentActivity; private Context actvityContext; private ActionBar actionBar; private boolean isActionBarVisible = true; private boolean isPhotosListViewVisible; private AnimatorSet actionBarAnimator; private int currentAccount; private static final int PROGRESS_NONE = -1; private static final int PROGRESS_EMPTY = 0; private static final int PROGRESS_CANCEL = 1; private static final int PROGRESS_LOAD = 2; private static final int PROGRESS_PLAY = 3; private static final int PROGRESS_PAUSE = 4; private static Drawable[] progressDrawables; private WindowManager.LayoutParams windowLayoutParams; private FrameLayoutDrawer containerView; private FrameLayout windowView; private ClippingImageView animatingImageView; private FrameLayout bottomLayout; private FadingTextViewLayout nameTextView; private FadingTextViewLayout dateTextView; private TextView docNameTextView; private TextView docInfoTextView; private ActionBarMenuItem menuItem; private ActionBarMenuSubItem allMediaItem; private ActionBarMenuItem sendNoQuoteItem; private ActionBarMenuItem sendItem; private ActionBarMenuItem pipItem; private ActionBarMenuItem masksItem; private Map actionBarItemsVisibility = new HashMap<>(3); private ImageView shareButton; private BackgroundDrawable backgroundDrawable = new BackgroundDrawable(0xff000000); private Paint blackPaint = new Paint(); private CheckBox checkImageView; private CounterView photosCounterView; private FrameLayout pickerView; private ImageView pickerViewSendButton; private PickerBottomLayoutViewer editorDoneLayout; private TextView resetButton; private PhotoProgressView[] photoProgressViews = new PhotoProgressView[3]; private RadialProgressView miniProgressView; private ImageView paintItem; private ImageView cropItem; private ImageView rotateItem; private ImageView cameraItem; private ImageView tuneItem; private ImageView timeItem; private ImageView muteItem; private ImageView compressItem; private GroupedPhotosListView groupedPhotosListView; private Tooltip tooltip; private SelectedPhotosListView selectedPhotosListView; private ListAdapter selectedPhotosAdapter; private AnimatorSet compressItemAnimation; private ImageReceiver sideImage; private boolean isCurrentVideo; private long lastPhotoSetTime; private GradientDrawable[] pressedDrawable = new GradientDrawable[2]; private boolean[] drawPressedDrawable = new boolean[2]; private float[] pressedDrawableAlpha = new float[2]; private int touchSlop; private boolean useSmoothKeyboard; private VideoForwardDrawable videoForwardDrawable; private AnimatorSet currentListViewAnimation; private PhotoCropView photoCropView; private PhotoFilterView photoFilterView; private PhotoPaintView photoPaintView; private AlertDialog visibleDialog; private CaptionTextViewSwitcher captionTextViewSwitcher; private CaptionScrollView captionScrollView; private FrameLayout captionContainer; private ChatAttachAlert parentAlert; private PhotoViewerCaptionEnterView captionEditText; private int sendPhotoType; private boolean isDocumentsPicker; private boolean needCaptionLayout; private AnimatedFileDrawable currentAnimation; private boolean allowShare; private boolean openedFullScreenVideo; private boolean dontChangeCaptionPosition; private boolean captionHwLayerEnabled; private Paint bitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG); private boolean pipAvailable; private Object lastInsets; private boolean padImageForHorizontalInsets; private boolean doneButtonPressed; private Runnable setLoadingRunnable = new Runnable() { @Override public void run() { if (currentMessageObject == null) { return; } FileLoader.getInstance(currentMessageObject.currentAccount).setLoadingVideo(currentMessageObject.getDocument(), true, false); } }; private Runnable hideActionBarRunnable = new Runnable() { @Override public void run() { if (videoPlayerControlVisible && isPlaying && !ApplicationLoader.mainInterfacePaused) { if (menuItem != null && menuItem.isSubMenuShowing()) { return; } if (captionScrollView != null && captionScrollView.getScrollY() != 0) { return; } if (miniProgressView != null && miniProgressView.getVisibility() == View.VISIBLE) { return; } toggleActionBar(false, true); } } }; private AspectRatioFrameLayout aspectRatioFrameLayout; private TextureView videoTextureView; private VideoPlayer videoPlayer; private VideoPlayer injectingVideoPlayer; private SurfaceTexture injectingVideoPlayerSurface; private boolean playerInjected; private boolean skipFirstBufferingProgress; private boolean playerWasReady; private boolean playerWasPlaying; private boolean playerAutoStarted; private boolean playerLooping; private float seekToProgressPending; private String shouldSavePositionForCurrentVideo; private String shouldSavePositionForCurrentVideoShortTerm; private ArrayMap savedVideoPositions = new ArrayMap<>(); private long lastSaveTime; private float seekToProgressPending2; private boolean streamingAlertShown; private long startedPlayTime; private boolean keepScreenOnFlagSet; private VideoPlayerControlFrameLayout videoPlayerControlFrameLayout; private Animator videoPlayerControlAnimator; private boolean videoPlayerControlVisible = true; private SimpleTextView videoPlayerTime; private VideoPlayerSeekBar videoPlayerSeekbar; private View videoPlayerSeekbarView; private VideoSeekPreviewImage videoPreviewFrame; private AnimatorSet videoPreviewFrameAnimation; private boolean needShowOnReady; private PipVideoView pipVideoView; private int waitingForDraw; private TextureView changedTextureView; private ImageView textureImageView; private int[] pipPosition = new int[2]; private boolean pipAnimationInProgress; private Bitmap currentBitmap; private boolean changingTextureView; private int waitingForFirstTextureUpload; private boolean textureUploaded; private boolean isInline; private boolean switchingInlineMode; private boolean videoCrossfadeStarted; private float videoCrossfadeAlpha; private long videoCrossfadeAlphaLastTime; private boolean isPlaying; private boolean isStreaming; private boolean firstAnimationDelay; private long lastBufferedPositionCheck; private View playButtonAccessibilityOverlay; private StickersAlert masksAlert; private int keyboardSize; private int currentPanTranslationY; public final static int SELECT_TYPE_AVATAR = 1; public final static int SELECT_TYPE_WALLPAPER = 3; public final static int SELECT_TYPE_QR = 10; private static class SavedVideoPosition { public final float position; public final long timestamp; public SavedVideoPosition(float position, long timestamp) { this.position = position; this.timestamp = timestamp; } } private class LinkMovementMethodMy extends LinkMovementMethod { @Override public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer, @NonNull MotionEvent event) { try { int action = event.getAction(); boolean result = false; if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { int x = (int) event.getX(); int y = (int) event.getY(); x -= widget.getTotalPaddingLeft(); y -= widget.getTotalPaddingTop(); x += widget.getScrollX(); y += widget.getScrollY(); Layout layout = widget.getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class); if (links.length != 0) { ClickableSpan link = links[0]; if (action == MotionEvent.ACTION_UP) { if (link instanceof URLSpan) { String url = ((URLSpan) link).getURL(); if (parentChatActivity != null && AndroidUtilities.shouldShowUrlInAlert(url)) { AlertsCreator.showOpenUrlAlert(parentChatActivity, url, true, true); } else { link.onClick(widget); } } else { link.onClick(widget); } } else if (action == MotionEvent.ACTION_DOWN) { Selection.setSelection(buffer, buffer.getSpanStart(link), buffer.getSpanEnd(link)); } result = true; } else { Selection.removeSelection(buffer); } } if (!result) { result = Touch.onTouchEvent(widget, buffer, event); } if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { AndroidUtilities.runOnUIThread(() -> widget.setOnClickListener(openCaptionEnter)); URLSpanNoUnderline[] links = buffer.getSpans(widget.getSelectionStart(), widget.getSelectionEnd(), URLSpanNoUnderline.class); if (links != null && links.length > 0) { String url = links[0].getURL(); if (url.startsWith("video")) { if (videoPlayer != null && currentMessageObject != null) { int seconds = Utilities.parseInt(url); if (videoPlayer.getDuration() == C.TIME_UNSET) { seekToProgressPending = seconds / (float) currentMessageObject.getDuration(); } else { videoPlayer.seekTo(seconds * 1000L); } } } else if (url.startsWith("#")) { if (parentActivity instanceof LaunchActivity) { DialogsActivity fragment = new DialogsActivity(null); fragment.setSearchString(url); ((LaunchActivity) parentActivity).presentFragment(fragment, false, true); closePhoto(false, false); } } } Selection.removeSelection(buffer); } return result; } catch (Exception e) { FileLog.e(e); } return false; } } private Runnable updateProgressRunnable = new Runnable() { @Override public void run() { if (videoPlayer != null) { if (isCurrentVideo) { if (!videoTimelineView.isDragging()) { float progress = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration(); if (!inPreview && (currentEditMode != 0 || videoTimelineView.getVisibility() == View.VISIBLE)) { if (progress >= videoTimelineView.getRightProgress()) { videoTimelineView.setProgress(0); videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); if (muteVideo || currentEditMode != 0) { videoPlayer.play(); } else { videoPlayer.pause(); } containerView.invalidate(); } else { progress -= videoTimelineView.getLeftProgress(); if (progress < 0) { progress = 0; } progress /= (videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()); if (progress > 1) { progress = 1; } videoTimelineView.setProgress(progress); } } else { videoTimelineView.setProgress(progress); } updateVideoPlayerTime(); } } else { float progress = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration(); float bufferedProgress; if (currentVideoFinishedLoading) { bufferedProgress = 1.0f; } else { long newTime = SystemClock.elapsedRealtime(); if (Math.abs(newTime - lastBufferedPositionCheck) >= 500) { bufferedProgress = isStreaming ? FileLoader.getInstance(currentAccount).getBufferedProgressFromPosition(seekToProgressPending != 0 ? seekToProgressPending : progress, currentFileNames[0]) : 1.0f; lastBufferedPositionCheck = newTime; } else { bufferedProgress = -1; } } if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { if (progress >= videoTimelineView.getRightProgress()) { videoPlayer.pause(); videoPlayerSeekbar.setProgress(0); videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); containerView.invalidate(); } else { progress -= videoTimelineView.getLeftProgress(); if (progress < 0) { progress = 0; } progress /= (videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()); if (progress > 1) { progress = 1; } videoPlayerSeekbar.setProgress(progress); } } else { if (seekToProgressPending == 0) { videoPlayerSeekbar.setProgress(progress); } if (bufferedProgress != -1) { videoPlayerSeekbar.setBufferedProgress(bufferedProgress); if (pipVideoView != null) { pipVideoView.setBufferedProgress(bufferedProgress); } } } videoPlayerSeekbarView.invalidate(); if (shouldSavePositionForCurrentVideo != null) { float value = progress; if (value >= 0 && shouldSavePositionForCurrentVideo != null && SystemClock.elapsedRealtime() - lastSaveTime >= 1000) { String saveFor = shouldSavePositionForCurrentVideo; lastSaveTime = SystemClock.elapsedRealtime(); Utilities.globalQueue.postRunnable(() -> { SharedPreferences.Editor editor = ApplicationLoader.applicationContext.getSharedPreferences("media_saved_pos", Activity.MODE_PRIVATE).edit(); editor.putFloat(shouldSavePositionForCurrentVideo, value).apply(); }); } } updateVideoPlayerTime(); } } if (isPlaying) { AndroidUtilities.runOnUIThread(updateProgressRunnable, 17); } } }; private Runnable switchToInlineRunnable = new Runnable() { @Override public void run() { switchingInlineMode = false; if (currentBitmap != null) { currentBitmap.recycle(); currentBitmap = null; } changingTextureView = true; if (textureImageView != null) { try { currentBitmap = Bitmaps.createBitmap(videoTextureView.getWidth(), videoTextureView.getHeight(), Bitmap.Config.ARGB_8888); videoTextureView.getBitmap(currentBitmap); } catch (Throwable e) { if (currentBitmap != null) { currentBitmap.recycle(); currentBitmap = null; } FileLog.e(e); } if (currentBitmap != null) { textureImageView.setVisibility(View.VISIBLE); textureImageView.setImageBitmap(currentBitmap); } else { textureImageView.setImageDrawable(null); } } isInline = true; pipVideoView = new PipVideoView(false); changedTextureView = pipVideoView.show(parentActivity, PhotoViewer.this, aspectRatioFrameLayout.getAspectRatio(), aspectRatioFrameLayout.getVideoRotation()); changedTextureView.setVisibility(View.INVISIBLE); aspectRatioFrameLayout.removeView(videoTextureView); } }; private TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { if (videoTextureView == null) { return true; } if (changingTextureView) { if (switchingInlineMode) { waitingForFirstTextureUpload = 2; } videoTextureView.setSurfaceTexture(surface); videoTextureView.setVisibility(View.VISIBLE); changingTextureView = false; containerView.invalidate(); return false; } return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { if (waitingForFirstTextureUpload == 1) { changedTextureView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { changedTextureView.getViewTreeObserver().removeOnPreDrawListener(this); if (textureImageView != null) { textureImageView.setVisibility(View.INVISIBLE); textureImageView.setImageDrawable(null); if (currentBitmap != null) { currentBitmap.recycle(); currentBitmap = null; } } AndroidUtilities.runOnUIThread(() -> { if (isInline) { dismissInternal(); } }); waitingForFirstTextureUpload = 0; return true; } }); changedTextureView.invalidate(); } } }; private float[][] animationValues = new float[2][13]; private ChatActivity parentChatActivity; private MentionsAdapter mentionsAdapter; private RecyclerListView mentionListView; private LinearLayoutManager mentionLayoutManager; private AnimatorSet mentionListAnimation; private boolean allowMentions; private ActionBarPopupWindow sendPopupWindow; private ActionBarPopupWindow.ActionBarPopupWindowLayout sendPopupLayout; private int animationInProgress; private boolean openAnimationInProgress; private long transitionAnimationStartTime; private Runnable animationEndRunnable; private PlaceProviderObject showAfterAnimation; private PlaceProviderObject hideAfterAnimation; private boolean disableShowCheck; private String lastTitle; private int currentEditMode; private final Runnable updateContainerFlagsRunnable = () -> { if (isVisible && animationInProgress == 0) { updateContainerFlags(isActionBarVisible); } }; private PaintingOverlay paintingOverlay; private ImageReceiver leftImage = new ImageReceiver(); private ImageReceiver centerImage = new ImageReceiver(); private ImageReceiver rightImage = new ImageReceiver(); private int currentIndex; private int switchingToIndex; private MessageObject currentMessageObject; private Uri currentPlayingVideoFile; private MediaController.SavedFilterState currentSavedFilterState; private ArrayList currentMediaEntities; private String currentPaintPath; private long currentAverageDuration; private TLRPC.BotInlineResult currentBotInlineResult; private ImageLocation currentFileLocation; private SecureDocument currentSecureDocument; private String[] currentFileNames = new String[3]; private PlaceProviderObject currentPlaceObject; private String currentPathObject; private String currentImagePath; private boolean currentVideoFinishedLoading; private ImageReceiver.BitmapHolder currentThumb; private boolean ignoreDidSetImage; boolean fromCamera; private int avatarsDialogId; private boolean isEvent; private int sharedMediaType; 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; 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 boolean applying; private long animationStartTime; private AnimatorSet imageMoveAnimation; private AnimatorSet changeModeAnimation; private GestureDetector2 gestureDetector; private boolean doubleTapEnabled; 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; private boolean zooming; private boolean moving; private int paintViewTouched; private boolean doubleTap; private boolean invalidCoords; private boolean canDragDown = true; private boolean zoomAnimation; private boolean discardTap; private int switchImageAfterAnimation; private VelocityTracker velocityTracker; private Scroller scroller; private boolean bottomTouchEnabled = true; private ArrayList imagesArrTemp = new ArrayList<>(); private SparseArray[] imagesByIdsTemp = new SparseArray[]{new SparseArray<>(), new SparseArray<>()}; private ArrayList imagesArr = new ArrayList<>(); private SparseArray[] imagesByIds = new SparseArray[]{new SparseArray<>(), new SparseArray<>()}; private ArrayList imagesArrLocations = new ArrayList<>(); private ArrayList secureDocuments = new ArrayList<>(); private ArrayList avatarsArr = new ArrayList<>(); private ArrayList imagesArrLocationsSizes = new ArrayList<>(); private ArrayList imagesArrLocals = new ArrayList<>(); private ImageLocation currentUserAvatarLocation = null; private android.graphics.Rect hitRect = new android.graphics.Rect(); private final static int gallery_menu_save = 1; private final static int gallery_menu_scan = 8; private final static int gallery_menu_showall = 2; private final static int gallery_menu_send = 3; private final static int gallery_menu_send_noquote = 93; private final static int gallery_menu_showinchat = 4; private final static int gallery_menu_pip = 5; private final static int gallery_menu_delete = 6; private final static int gallery_menu_cancel_loading = 7; private final static int gallery_menu_share = 10; private final static int gallery_menu_openin = 11; private final static int gallery_menu_masks = 13; private final static int gallery_menu_savegif = 14; private final static int gallery_menu_masks2 = 15; private final static int gallery_menu_setascurrent = 94; private static DecelerateInterpolator decelerateInterpolator; private static Paint progressPaint; private int transitionIndex; private class BackgroundDrawable extends ColorDrawable { private final RectF rect = new RectF(); private final RectF visibleRect = new RectF(); private final Paint paint; private Runnable drawRunnable; private boolean allowDrawContent; public BackgroundDrawable(int color) { super(color); paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(color); } @Keep @Override public void setAlpha(int alpha) { if (parentActivity instanceof LaunchActivity) { allowDrawContent = !isVisible || alpha != 255; ((LaunchActivity) parentActivity).drawerLayoutContainer.setAllowDrawContent(allowDrawContent); if (parentAlert != null) { if (!allowDrawContent) { AndroidUtilities.runOnUIThread(() -> { if (parentAlert != null) { parentAlert.setAllowDrawContent(allowDrawContent); } }, 50); } else { if (parentAlert != null) { parentAlert.setAllowDrawContent(allowDrawContent); } } } } super.setAlpha(alpha); paint.setAlpha(alpha); } @Override public void draw(Canvas canvas) { if (animationInProgress != 0 && !AndroidUtilities.isTablet() && currentPlaceObject != null && currentPlaceObject.animatingImageView != null) { animatingImageView.getClippedVisibleRect(visibleRect); if (!visibleRect.isEmpty()) { visibleRect.inset(AndroidUtilities.dp(1f), AndroidUtilities.dp(1f)); final Rect boundsRect = getBounds(); final float width = boundsRect.right; final float height = boundsRect.bottom; for (int i = 0; i < 4; i++) { switch (i) { case 0: // left rect rect.set(0, visibleRect.top, visibleRect.left, visibleRect.bottom); break; case 1: // top rect rect.set(0, 0, width, visibleRect.top); break; case 2: // right rect rect.set(visibleRect.right, visibleRect.top, width, visibleRect.bottom); break; case 3: // bottom rect rect.set(0, visibleRect.bottom, width, height); break; } canvas.drawRect(rect, paint); } } } else { super.draw(canvas); } if (getAlpha() != 0) { if (drawRunnable != null) { AndroidUtilities.runOnUIThread(drawRunnable); drawRunnable = null; } } } } private static class SelectedPhotosListView extends RecyclerListView { private Drawable arrowDrawable; private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private RectF rect = new RectF(); public SelectedPhotosListView(Context context) { super(context); setWillNotDraw(false); setClipToPadding(false); setTranslationY(-AndroidUtilities.dp(10)); DefaultItemAnimator defaultItemAnimator; setItemAnimator(defaultItemAnimator = new DefaultItemAnimator() { @Override protected void onMoveAnimationUpdate(ViewHolder holder) { invalidate(); } }); defaultItemAnimator.setDelayAnimations(false); defaultItemAnimator.setSupportsChangeAnimations(false); setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(12), AndroidUtilities.dp(12), AndroidUtilities.dp(6)); paint.setColor(0x7f000000); arrowDrawable = context.getResources().getDrawable(R.drawable.photo_tooltip2).mutate(); } @Override public void onDraw(Canvas c) { super.onDraw(c); int count = getChildCount(); if (count > 0) { int x = getMeasuredWidth() - AndroidUtilities.dp(87); arrowDrawable.setBounds(x, 0, x + arrowDrawable.getIntrinsicWidth(), AndroidUtilities.dp(6)); arrowDrawable.draw(c); int minX = Integer.MAX_VALUE; int maxX = Integer.MIN_VALUE; for (int a = 0; a < count; a++) { View v = getChildAt(a); minX = (int) Math.min(minX, Math.floor(v.getX())); maxX = (int) Math.max(maxX, Math.ceil(v.getX() + v.getMeasuredWidth())); } if (minX != Integer.MAX_VALUE && maxX != Integer.MIN_VALUE) { rect.set(minX - AndroidUtilities.dp(6), AndroidUtilities.dp(6), maxX + AndroidUtilities.dp(6), AndroidUtilities.dp(6 + 85 + 12)); c.drawRoundRect(rect, AndroidUtilities.dp(8), AndroidUtilities.dp(8), paint); } } } } private static class CounterView extends View { private StaticLayout staticLayout; private TextPaint textPaint; private Paint paint; private int width; private int height; private RectF rect; private int currentCount = 0; private float rotation; public CounterView(Context context) { super(context); textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); textPaint.setTextSize(AndroidUtilities.dp(15)); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); textPaint.setColor(0xffffffff); paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(0xffffffff); paint.setStrokeWidth(AndroidUtilities.dp(2)); paint.setStyle(Paint.Style.STROKE); paint.setStrokeJoin(Paint.Join.ROUND); rect = new RectF(); setCount(0); } @Keep @Override public void setScaleX(float scaleX) { super.setScaleX(scaleX); invalidate(); } @Keep @Override public void setRotationX(float rotationX) { rotation = rotationX; invalidate(); } @Override public float getRotationX() { return rotation; } public void setCount(int value) { staticLayout = new StaticLayout("" + Math.max(1, value), textPaint, AndroidUtilities.dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); width = (int) Math.ceil(staticLayout.getLineWidth(0)); height = staticLayout.getLineBottom(0); AnimatorSet animatorSet = new AnimatorSet(); if (value == 0) { animatorSet.playTogether( ObjectAnimator.ofFloat(this, View.SCALE_X, 0.0f), ObjectAnimator.ofFloat(this, View.SCALE_Y, 0.0f), ObjectAnimator.ofInt(paint, AnimationProperties.PAINT_ALPHA, 0), ObjectAnimator.ofInt(textPaint, AnimationProperties.PAINT_ALPHA, 0)); animatorSet.setInterpolator(new DecelerateInterpolator()); } else if (currentCount == 0) { animatorSet.playTogether( ObjectAnimator.ofFloat(this, View.SCALE_X, 0.0f, 1.0f), ObjectAnimator.ofFloat(this, View.SCALE_Y, 0.0f, 1.0f), ObjectAnimator.ofInt(paint, AnimationProperties.PAINT_ALPHA, 0, 255), ObjectAnimator.ofInt(textPaint, AnimationProperties.PAINT_ALPHA, 0, 255)); animatorSet.setInterpolator(new DecelerateInterpolator()); } else if (value < currentCount) { animatorSet.playTogether( ObjectAnimator.ofFloat(this, View.SCALE_X, 1.1f, 1.0f), ObjectAnimator.ofFloat(this, View.SCALE_Y, 1.1f, 1.0f)); animatorSet.setInterpolator(new OvershootInterpolator()); } else { animatorSet.playTogether( ObjectAnimator.ofFloat(this, View.SCALE_X, 0.9f, 1.0f), ObjectAnimator.ofFloat(this, View.SCALE_Y, 0.9f, 1.0f)); animatorSet.setInterpolator(new OvershootInterpolator()); } animatorSet.setDuration(180); animatorSet.start(); requestLayout(); currentCount = value; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(MeasureSpec.makeMeasureSpec(Math.max(width + AndroidUtilities.dp(20), AndroidUtilities.dp(30)), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(40), MeasureSpec.EXACTLY)); } @Override protected void onDraw(Canvas canvas) { int cy = getMeasuredHeight() / 2; paint.setAlpha(255); rect.set(AndroidUtilities.dp(1), cy - AndroidUtilities.dp(14), getMeasuredWidth() - AndroidUtilities.dp(1), cy + AndroidUtilities.dp(14)); canvas.drawRoundRect(rect, AndroidUtilities.dp(15), AndroidUtilities.dp(15), paint); if (staticLayout != null) { textPaint.setAlpha((int) ((1.0f - rotation) * 255)); canvas.save(); canvas.translate((getMeasuredWidth() - width) / 2, (getMeasuredHeight() - height) / 2 + AndroidUtilities.dpf2(0.2f) + rotation * AndroidUtilities.dp(5)); staticLayout.draw(canvas); canvas.restore(); paint.setAlpha((int) (rotation * 255)); int cx = (int) rect.centerX(); cy = (int) rect.centerY(); cy -= AndroidUtilities.dp(5) * (1.0f - rotation); canvas.drawLine(cx + AndroidUtilities.dp(5), cy - AndroidUtilities.dp(5), cx - AndroidUtilities.dp(5), cy + AndroidUtilities.dp(5), paint); canvas.drawLine(cx - AndroidUtilities.dp(5), cy - AndroidUtilities.dp(5), cx + AndroidUtilities.dp(5), cy + AndroidUtilities.dp(5), paint); } } } private class PhotoProgressView { 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; private int size = AndroidUtilities.dp(64); private int previousBackgroundState = -2; private float animatedAlphaValue = 1.0f; private float[] animAlphas = new float[3]; private float[] alphas = new float[3]; private float scale = 1.0f; private boolean visible; public PhotoProgressView(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; resetAlphas(); } private void updateAnimation(boolean withProgressAnimation) { long newTime = System.currentTimeMillis(); long dt = newTime - lastUpdateTime; if (dt > 18) { dt = 18; } lastUpdateTime = newTime; boolean postInvalidate = false; if (withProgressAnimation) { if (animatedProgressValue != 1 || currentProgress != 1) { radOffset += 360 * dt / 3000.0f; float progressDiff = currentProgress - animationProgressStart; if (Math.abs(progressDiff) > 0) { currentProgressTime += dt; if (currentProgressTime >= 300) { animatedProgressValue = currentProgress; animationProgressStart = currentProgress; currentProgressTime = 0; } else { animatedProgressValue = animationProgressStart + progressDiff * decelerateInterpolator.getInterpolation(currentProgressTime / 300.0f); } } postInvalidate = true; } if (animatedAlphaValue > 0 && previousBackgroundState != -2) { animatedAlphaValue -= dt / 200.0f; if (animatedAlphaValue <= 0) { animatedAlphaValue = 0.0f; previousBackgroundState = -2; } postInvalidate = true; } } for (int i = 0; i < alphas.length; i++) { if (alphas[i] > animAlphas[i]) { animAlphas[i] = Math.min(1f, animAlphas[i] + dt / 200f); postInvalidate = true; } else if (alphas[i] < animAlphas[i]) { animAlphas[i] = Math.max(0f, animAlphas[i] - dt / 200f); postInvalidate = true; } } if (postInvalidate) { parent.postInvalidateOnAnimation(); } } public void setProgress(float value, boolean animated) { if (!animated) { animatedProgressValue = value; animationProgressStart = value; } else { animationProgressStart = animatedProgressValue; } currentProgress = value; currentProgressTime = 0; parent.invalidate(); } public void setBackgroundState(int state, boolean animated) { if (backgroundState == state) { return; } lastUpdateTime = System.currentTimeMillis(); if (animated && backgroundState != state) { previousBackgroundState = backgroundState; animatedAlphaValue = 1.0f; } else { previousBackgroundState = -2; } onBackgroundStateUpdated(backgroundState = state); parent.invalidate(); } protected void onBackgroundStateUpdated(int state) { } public void setAlpha(float value) { alphas[0] = animAlphas[0] = value; checkVisibility(); } public void setScale(float value) { scale = value; } public void setIndexedAlpha(int index, float alpha, boolean animated) { if (alphas[index] != alpha) { alphas[index] = alpha; if (!animated) { animAlphas[index] = alpha; } checkVisibility(); parent.invalidate(); } } public void resetAlphas() { for (int i = 0; i < alphas.length; i++) { alphas[i] = animAlphas[i] = 1.0f; } checkVisibility(); } private float calculateAlpha() { float alpha = 1.0f; for (int i = 0; i < animAlphas.length; i++) { if (i == 2) { alpha *= AndroidUtilities.accelerateInterpolator.getInterpolation(animAlphas[i]); } else { alpha *= animAlphas[i]; } } return alpha; } private void checkVisibility() { boolean newVisible = true; for (int i = 0; i < alphas.length; i++) { if (alphas[i] != 1.0f) { newVisible = false; break; } } if (newVisible != visible) { visible = newVisible; onVisibilityChanged(visible); } } protected void onVisibilityChanged(boolean visible) { } public boolean isVisible() { return visible; } public int getX() { return (getContainerViewWidth() - (int) (size * scale)) / 2; } public int getY() { return (getContainerViewHeight() - (int) (size * scale)) / 2; } public void onDraw(Canvas canvas) { int sizeScaled = (int) (size * scale); int x = getX(); int y = getY(); final float alpha = calculateAlpha(); if (previousBackgroundState >= 0 && previousBackgroundState < progressDrawables.length) { 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 < progressDrawables.length) { 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 == PROGRESS_EMPTY || backgroundState == PROGRESS_CANCEL || previousBackgroundState == PROGRESS_EMPTY || previousBackgroundState == PROGRESS_CANCEL) { 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(true); } else { updateAnimation(false); } } } public static class PlaceProviderObject { public ImageReceiver imageReceiver; public int viewX; public int viewY; public View parentView; public ImageReceiver.BitmapHolder 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 boolean isEvent; public ClippingImageView animatingImageView; public int animatingImageViewYOffset; public boolean allowTakeAnimation = true; } public static class EmptyPhotoViewerProvider implements PhotoViewerProvider { @Override public PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index, boolean needPreview) { return null; } @Override public ImageReceiver.BitmapHolder 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 int setPhotoUnchecked(Object photoEntry) { return -1; } @Override public boolean isPhotoChecked(int index) { return false; } @Override public int setPhotoChecked(int index, VideoEditedInfo videoEditedInfo) { return -1; } @Override public boolean cancelButtonPressed() { return true; } @Override public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate) { } @Override public int getSelectedCount() { return 0; } @Override public void updatePhotoAtIndex(int index) { } @Override public boolean allowCaption() { return true; } @Override public boolean scaleToFill() { return false; } @Override public ArrayList getSelectedPhotosOrder() { return null; } @Override public HashMap getSelectedPhotos() { return null; } @Override public boolean canScrollAway() { return true; } @Override public void needAddMorePhotos() { } @Override public int getPhotoIndex(int index) { return -1; } @Override public void deleteImageAtIndex(int index) { } @Override public String getDeleteMessageString() { return null; } @Override public boolean canCaptureMorePhotos() { return true; } } public interface PhotoViewerProvider { PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index, boolean needPreview); ImageReceiver.BitmapHolder getThumbForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index); void willSwitchFromPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index); void willHidePhotoViewer(); boolean isPhotoChecked(int index); int setPhotoChecked(int index, VideoEditedInfo videoEditedInfo); int setPhotoUnchecked(Object photoEntry); boolean cancelButtonPressed(); void needAddMorePhotos(); void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate); int getSelectedCount(); void updatePhotoAtIndex(int index); boolean allowCaption(); boolean scaleToFill(); ArrayList getSelectedPhotosOrder(); HashMap getSelectedPhotos(); boolean canScrollAway(); int getPhotoIndex(int index); void deleteImageAtIndex(int index); String getDeleteMessageString(); boolean canCaptureMorePhotos(); } private class FrameLayoutDrawer extends SizeNotifierFrameLayoutPhoto { private Paint paint = new Paint(); private boolean ignoreLayout; private boolean captionAbove; public FrameLayoutDrawer(Context context) { super(context, false); 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); if (!isCurrentVideo) { ignoreLayout = true; if (needCaptionLayout) { final int maxLines = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? 5 : 10; captionTextViewSwitcher.getCurrentView().setMaxLines(maxLines); captionTextViewSwitcher.getNextView().setMaxLines(maxLines); } else { captionTextViewSwitcher.getCurrentView().setMaxLines(Integer.MAX_VALUE); captionTextViewSwitcher.getNextView().setMaxLines(Integer.MAX_VALUE); } ignoreLayout = false; } measureChildWithMargins(captionEditText, widthMeasureSpec, 0, heightMeasureSpec, 0); int inputFieldHeight = captionEditText.getMeasuredHeight(); final int groupedPhotosHeight; if (groupedPhotosListView != null && groupedPhotosListView.getVisibility() != GONE) { measureChildWithMargins(groupedPhotosListView, widthMeasureSpec, 0, heightMeasureSpec, 0); groupedPhotosHeight = groupedPhotosListView.getMeasuredHeight(); } else { groupedPhotosHeight = 0; } widthSize -= (getPaddingRight() + getPaddingLeft()); heightSize -= getPaddingBottom(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child.getVisibility() == GONE || child == captionEditText || child == groupedPhotosListView) { continue; } if (child == aspectRatioFrameLayout) { int heightSpec = MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0), MeasureSpec.EXACTLY); child.measure(widthMeasureSpec, heightSpec); } else if (child == paintingOverlay) { int width; int height; if (aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == VISIBLE) { width = videoTextureView.getMeasuredWidth(); height = videoTextureView.getMeasuredHeight(); } else { width = centerImage.getBitmapWidth(); height = centerImage.getBitmapHeight(); } if (width == 0 || height == 0) { width = widthSize; height = heightSize; } paintingOverlay.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); } else 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 if (child == captionScrollView) { int bottomMargin = AndroidUtilities.dp(48); if (dontChangeCaptionPosition) { if (captionAbove) { bottomMargin += groupedPhotosHeight; } } else if (groupedPhotosListView.hasPhotos()) { bottomMargin += groupedPhotosHeight; captionAbove = true; } else { captionAbove = false; } final int topMargin = (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight(); final int height = heightSize - topMargin - bottomMargin; ((MarginLayoutParams) captionScrollView.getLayoutParams()).bottomMargin = bottomMargin; child.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(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(); keyboardSize = useSmoothKeyboard ? 0 : getKeyboardHeight(); int paddingBottom = keyboardSize <= 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; } int l, r, b; if (child == aspectRatioFrameLayout) { l = _l; r = _r; b = _b; } else { l = _l + getPaddingLeft(); r = _r - getPaddingRight(); b = _b - getPaddingBottom(); } 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 - l - width) - lp.rightMargin; break; case Gravity.LEFT: default: childLeft = lp.leftMargin; } switch (verticalGravity) { 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; break; } if (child == mentionListView) { childTop -= captionEditText.getMeasuredHeight(); } else if (captionEditText.isPopupView(child)) { if (AndroidUtilities.isInMultiwindow) { childTop = captionEditText.getTop() - child.getMeasuredHeight() + AndroidUtilities.dp(1); } else { childTop = captionEditText.getBottom(); } } else if (child == selectedPhotosListView) { childTop = actionBar.getMeasuredHeight() + AndroidUtilities.dp(5); } else if (child == cameraItem || child == muteItem) { final int top; if (videoTimelineView != null && videoTimelineView.getVisibility() == VISIBLE) { top = videoTimelineView.getTop(); } else { top = pickerView.getTop(); } childTop = top - AndroidUtilities.dp(sendPhotoType == 4 || sendPhotoType == 5 ? 40 : 15) - child.getMeasuredHeight(); } else if (child == videoTimelineView) { childTop -= pickerView.getHeight(); } child.layout(childLeft + l, childTop, childLeft + width + l, childTop + height); } notifyHeightChanged(); } @Override protected void onDraw(Canvas canvas) { PhotoViewer.this.onDraw(canvas); if (Build.VERSION.SDK_INT >= 21 && AndroidUtilities.statusBarHeight != 0 && actionBar != null) { paint.setAlpha((int) (255 * actionBar.getAlpha() * 0.2f)); canvas.drawRect(0, currentPanTranslationY, getMeasuredWidth(), currentPanTranslationY + AndroidUtilities.statusBarHeight, paint); paint.setAlpha((int) (255 * actionBar.getAlpha() * 0.498f)); if (getPaddingRight() > 0) { canvas.drawRect(getMeasuredWidth() - getPaddingRight(), 0, getMeasuredWidth(), getMeasuredHeight(), paint); } if (getPaddingLeft() > 0) { canvas.drawRect(0, 0, getPaddingLeft(), getMeasuredHeight(), paint); } } } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == mentionListView || child == captionEditText) { if (currentEditMode != 0 || !captionEditText.isPopupShowing() && captionEditText.getEmojiPadding() == 0 && (AndroidUtilities.usingHardwareInput && captionEditText.getTag() == null || getKeyboardHeight() == 0)) { return false; } } else if (child == cameraItem || child == muteItem || child == pickerView || child == videoTimelineView || child == pickerViewSendButton || child == captionTextViewSwitcher || muteItem.getVisibility() == VISIBLE && child == bottomLayout) { int paddingBottom = getKeyboardHeight() <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow ? captionEditText.getEmojiPadding() : 0; if (captionEditText.isPopupShowing() || AndroidUtilities.usingHardwareInput && captionEditText.getTag() != null || getKeyboardHeight() > AndroidUtilities.dp(80) || paddingBottom != 0) { bottomTouchEnabled = false; return false; } else { bottomTouchEnabled = true; } } else if (child == checkImageView || child == photosCounterView) { if (captionEditText.getTag() != null) { bottomTouchEnabled = false; return false; } else { bottomTouchEnabled = true; } } else if (child == miniProgressView) { return false; } try { return child != aspectRatioFrameLayout && child != paintingOverlay && super.drawChild(canvas, child, drawingTime); } catch (Throwable ignore) { return true; } } @Override public void requestLayout() { if (ignoreLayout) { return; } super.requestLayout(); } @Override protected void onPanTranslationUpdate(int y) { currentPanTranslationY = y; actionBar.setTranslationY(y); if (miniProgressView != null) { miniProgressView.setTranslationY(y); } if (progressView != null) { progressView.setTranslationY(y); } if (checkImageView != null) { checkImageView.setTranslationY(y); } if (photosCounterView != null) { photosCounterView.setTranslationY(y); } if (selectedPhotosListView != null) { selectedPhotosListView.setTranslationY(y); } if (aspectRatioFrameLayout != null) { aspectRatioFrameLayout.setTranslationY(y); } if (textureImageView != null) { textureImageView.setTranslationY(y); } if (photoCropView != null) { photoCropView.setTranslationY(y); } if (photoFilterView != null) { photoFilterView.setTranslationY(y); } if (photoPaintView != null) { photoPaintView.setTranslationY(y); } invalidate(); } } private static final Property VPC_PROGRESS; static { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { VPC_PROGRESS = new FloatProperty("progress") { @Override public void setValue(VideoPlayerControlFrameLayout object, float value) { object.setProgress(value); } @Override public Float get(VideoPlayerControlFrameLayout object) { return object.getProgress(); } }; } else { VPC_PROGRESS = new Property(Float.class, "progress") { @Override public void set(VideoPlayerControlFrameLayout object, Float value) { object.setProgress(value); } @Override public Float get(VideoPlayerControlFrameLayout object) { return object.getProgress(); } }; } } private class VideoPlayerControlFrameLayout extends FrameLayout { private float progress = 1f; private boolean seekBarTransitionEnabled; public VideoPlayerControlFrameLayout(@NonNull Context context) { super(context); setWillNotDraw(false); } @Override public boolean onTouchEvent(MotionEvent event) { if (progress < 1f) { return false; } if (videoPlayerSeekbar.onTouch(event.getAction(), event.getX() - AndroidUtilities.dp(2), event.getY())) { getParent().requestDisallowInterceptTouchEvent(true); videoPlayerSeekbarView.invalidate(); return true; } return true; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); long duration; if (videoPlayer != null) { duration = videoPlayer.getDuration(); if (duration == C.TIME_UNSET) { duration = 0; } } else { duration = 0; } duration /= 1000; int size = (int) Math.ceil(videoPlayerTime.getPaint().measureText(String.format(Locale.ROOT, "%02d:%02d / %02d:%02d", duration / 60, duration % 60, duration / 60, duration % 60))); videoPlayerSeekbar.setSize(getMeasuredWidth() - AndroidUtilities.dp(2 + 14) - 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) { progress = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration(); if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { progress -= videoTimelineView.getLeftProgress(); if (progress < 0) { progress = 0; } progress /= (videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()); if (progress > 1) { progress = 1; } } } if (playerWasReady) { videoPlayerSeekbar.setProgress(progress); } videoTimelineView.setProgress(progress); } public float getProgress() { return progress; } public void setProgress(float progress) { if (this.progress != progress) { this.progress = progress; onProgressChanged(progress); } } private void onProgressChanged(float progress) { videoPlayerTime.setAlpha(progress); if (seekBarTransitionEnabled) { videoPlayerTime.setPivotX(videoPlayerTime.getWidth()); videoPlayerTime.setPivotY(videoPlayerTime.getHeight()); videoPlayerTime.setScaleX(1f - 0.1f * (1f - progress)); videoPlayerTime.setScaleY(1f - 0.1f * (1f - progress)); videoPlayerSeekbar.setTransitionProgress(1f - progress); } else { setTranslationY(AndroidUtilities.dpf2(24) * (1f - progress)); videoPlayerSeekbarView.setAlpha(progress); } } public boolean isSeekBarTransitionEnabled() { return seekBarTransitionEnabled; } public void setSeekBarTransitionEnabled(boolean seekBarTransitionEnabled) { if (this.seekBarTransitionEnabled != seekBarTransitionEnabled) { this.seekBarTransitionEnabled = seekBarTransitionEnabled; if (seekBarTransitionEnabled) { setTranslationY(0); videoPlayerSeekbarView.setAlpha(1f); } else { videoPlayerTime.setScaleX(1f); videoPlayerTime.setScaleY(1f); videoPlayerSeekbar.setTransitionProgress(0f); } onProgressChanged(progress); } } } private class CaptionTextViewSwitcher extends TextViewSwitcher { private boolean inScrollView = false; private float alpha = 1.0f; public CaptionTextViewSwitcher(Context context) { super(context); } @Override public void setVisibility(int visibility) { setVisibility(visibility, true); } public void setVisibility(int visibility, boolean withScrollView) { super.setVisibility(visibility); if (inScrollView && withScrollView) { captionScrollView.setVisibility(visibility); } } @Override public void setAlpha(float alpha) { this.alpha = alpha; if (inScrollView) { captionScrollView.setAlpha(alpha); } else { super.setAlpha(alpha); } } @Override public float getAlpha() { if (inScrollView) { return alpha; } else { return super.getAlpha(); } } @Override public void setTranslationY(float translationY) { super.setTranslationY(translationY); if (inScrollView) { captionScrollView.invalidate(); // invalidate background drawing } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (captionContainer != null && getParent() == captionContainer) { inScrollView = true; captionScrollView.setVisibility(getVisibility()); captionScrollView.setAlpha(alpha); super.setAlpha(1.0f); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (inScrollView) { inScrollView = false; captionScrollView.setVisibility(View.GONE); super.setAlpha(alpha); } } } private class CaptionScrollView extends NestedScrollView { private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private final SpringAnimation springAnimation; private boolean nestedScrollStarted; private float overScrollY; private float velocitySign; private float velocityY; private Method abortAnimatedScrollMethod; private OverScroller scroller; private boolean isLandscape; private int textHash; private int prevHeight; private float backgroundAlpha = 1f; private boolean dontChangeTopMargin; private int pendingTopMargin = -1; public CaptionScrollView(@NonNull Context context) { super(context); setClipChildren(false); setOverScrollMode(View.OVER_SCROLL_NEVER); paint.setColor(Color.BLACK); setFadingEdgeLength(AndroidUtilities.dp(12)); setVerticalFadingEdgeEnabled(true); setWillNotDraw(false); springAnimation = new SpringAnimation(captionTextViewSwitcher, DynamicAnimation.TRANSLATION_Y, 0); springAnimation.getSpring().setStiffness(100f); springAnimation.setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_PIXELS); springAnimation.addUpdateListener((animation, value, velocity) -> { overScrollY = value; velocityY = velocity; }); springAnimation.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY); try { abortAnimatedScrollMethod = NestedScrollView.class.getDeclaredMethod("abortAnimatedScroll"); abortAnimatedScrollMethod.setAccessible(true); } catch (Exception e) { abortAnimatedScrollMethod = null; FileLog.e(e); } try { final Field scrollerField = NestedScrollView.class.getDeclaredField("mScroller"); scrollerField.setAccessible(true); scroller = (OverScroller) scrollerField.get(this); } catch (Exception e) { scroller = null; FileLog.e(e); } } @Override public boolean onTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getY() < captionContainer.getTop() - getScrollY() + captionTextViewSwitcher.getTranslationY()) { return false; } return super.onTouchEvent(ev); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { updateTopMargin(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public void applyPendingTopMargin() { dontChangeTopMargin = false; if (pendingTopMargin >= 0) { ((MarginLayoutParams) captionContainer.getLayoutParams()).topMargin = pendingTopMargin; pendingTopMargin = -1; requestLayout(); } } public int getPendingMarginTopDiff() { if (pendingTopMargin >= 0) { return pendingTopMargin - ((MarginLayoutParams) captionContainer.getLayoutParams()).topMargin; } else { return 0; } } public void updateTopMargin() { updateTopMargin(getWidth(), getHeight()); } private void updateTopMargin(int width, int height) { final int marginTop = calculateNewContainerMarginTop(width, height); if (marginTop >= 0) { if (dontChangeTopMargin) { pendingTopMargin = marginTop; } else { ((MarginLayoutParams) captionContainer.getLayoutParams()).topMargin = marginTop; pendingTopMargin = -1; } } } public int calculateNewContainerMarginTop(int width, int height) { if (width == 0 || height == 0) { return -1; } final TextView textView = captionTextViewSwitcher.getCurrentView(); final CharSequence text = textView.getText(); final int textHash = text.hashCode(); final boolean isLandscape = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y; if (this.textHash == textHash && this.isLandscape == isLandscape && this.prevHeight == height) { return -1; } this.textHash = textHash; this.isLandscape = isLandscape; this.prevHeight = height; textView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); final Layout layout = textView.getLayout(); final int lineCount = layout.getLineCount(); if (isLandscape && lineCount <= 3 || !isLandscape && lineCount <= 5) { return height - textView.getMeasuredHeight(); } int i = Math.min(isLandscape ? 3 : 5, lineCount); cycle: while (i > 1) { for (int j = layout.getLineStart(i - 1); j < layout.getLineEnd(i - 1); j++) { if (Character.isLetterOrDigit(text.charAt(j))) { break cycle; } } i--; } final int lineHeight = textView.getPaint().getFontMetricsInt(null); return height - lineHeight * i - AndroidUtilities.dp(8); } public void reset() { scrollTo(0, 0); } public void stopScrolling() { if (abortAnimatedScrollMethod != null) { try { abortAnimatedScrollMethod.invoke(this); } catch (Exception e) { FileLog.e(e); } } } @Override public void fling(int velocityY) { super.fling(velocityY); this.velocitySign = Math.signum(velocityY); this.velocityY = 0f; } @Override public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow, int type) { consumed[1] = 0; if (nestedScrollStarted && (overScrollY > 0 && dy > 0 || overScrollY < 0 && dy < 0)) { final float delta = overScrollY - dy; if (overScrollY > 0) { if (delta < 0) { overScrollY = 0; consumed[1] += dy + delta; } else { overScrollY = delta; consumed[1] += dy; } } else { if (delta > 0) { overScrollY = 0; consumed[1] += dy + delta; } else { overScrollY = delta; consumed[1] += dy; } } captionTextViewSwitcher.setTranslationY(overScrollY); return true; } return false; } @Override public void dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow, int type, @NonNull int[] consumed) { if (dyUnconsumed != 0) { final int topMargin = (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight(); final int dy = Math.round(dyUnconsumed * (1f - Math.abs((-overScrollY / (captionContainer.getTop() - topMargin))))); if (dy != 0) { if (!nestedScrollStarted) { if (!springAnimation.isRunning()) { int consumedY; float velocity = scroller != null ? scroller.getCurrVelocity() : Float.NaN; if (!Float.isNaN(velocity)) { final float clampedVelocity = Math.min(AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? 3000 : 5000, velocity); consumedY = (int) (dy * clampedVelocity / velocity); velocity = clampedVelocity * -velocitySign; } else { consumedY = dy; velocity = 0; } if (consumedY != 0) { overScrollY -= consumedY; captionTextViewSwitcher.setTranslationY(overScrollY); } startSpringAnimationIfNotRunning(velocity); } } else { overScrollY -= dy; captionTextViewSwitcher.setTranslationY(overScrollY); } } } } private void startSpringAnimationIfNotRunning(float velocityY) { if (!springAnimation.isRunning()) { springAnimation.setStartVelocity(velocityY); springAnimation.start(); } } @Override public boolean startNestedScroll(int axes, int type) { if (type == ViewCompat.TYPE_TOUCH) { springAnimation.cancel(); nestedScrollStarted = true; overScrollY = captionTextViewSwitcher.getTranslationY(); } return true; } @Override public void computeScroll() { super.computeScroll(); if (!nestedScrollStarted && overScrollY != 0 && scroller != null && scroller.isFinished()) { startSpringAnimationIfNotRunning(0); } } @Override public void stopNestedScroll(int type) { if (nestedScrollStarted && type == ViewCompat.TYPE_TOUCH) { nestedScrollStarted = false; if (overScrollY != 0 && scroller != null && scroller.isFinished()) { startSpringAnimationIfNotRunning(velocityY); } } } @Override protected float getTopFadingEdgeStrength() { return 1f; } @Override protected float getBottomFadingEdgeStrength() { return 1f; } @Override public void draw(Canvas canvas) { paint.setAlpha((int) (backgroundAlpha * 127)); canvas.drawRect(0, captionContainer.getTop() + captionTextViewSwitcher.getTranslationY(), getWidth(), getHeight() + getScrollY(), paint); super.draw(canvas); } @Override public void invalidate() { super.invalidate(); if (isActionBarVisible) { final int progressBottom = photoProgressViews[0].getY() + photoProgressViews[0].size; final int topMargin = (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight(); final int captionTop = captionContainer.getTop() + (int) captionTextViewSwitcher.getTranslationY() - getScrollY() + topMargin - AndroidUtilities.dp(12); photoProgressViews[0].setIndexedAlpha(2, captionTop > progressBottom ? 1f : 0f, true); } } } @SuppressLint("StaticFieldLeak") private static volatile PhotoViewer Instance = null; private static volatile PhotoViewer PipInstance = null; public static PhotoViewer getPipInstance() { return PipInstance; } 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 boolean isOpenedFullScreenVideo() { return openedFullScreenVideo; } public static boolean hasInstance() { return Instance != null; } public PhotoViewer() { blackPaint.setColor(0xff000000); } @SuppressWarnings("unchecked") @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.fileDidFailToLoad) { String location = (String) args[0]; for (int a = 0; a < 3; a++) { if (currentFileNames[a] != null && currentFileNames[a].equals(location)) { boolean animated = a == 0 || a == 1 && sideImage == rightImage || a == 2 && sideImage == leftImage; photoProgressViews[a].setProgress(1.0f, animated); checkProgress(a, false, true); break; } } } else if (id == NotificationCenter.fileDidLoad) { String location = (String) args[0]; for (int a = 0; a < 3; a++) { if (currentFileNames[a] != null && currentFileNames[a].equals(location)) { boolean animated = a == 0 || a == 1 && sideImage == rightImage || a == 2 && sideImage == leftImage; photoProgressViews[a].setProgress(1.0f, animated); checkProgress(a, false, animated); if (videoPlayer == null && a == 0 && (currentMessageObject != null && currentMessageObject.isVideo() || currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document)))) { onActionClick(false); } if (a == 0 && videoPlayer != null) { currentVideoFinishedLoading = true; } 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)) { Long loadedSize = (Long) args[1]; Long totalSize = (Long) args[2]; float loadProgress = Math.min(1f, loadedSize / (float) totalSize); boolean animated = a == 0 || a == 1 && sideImage == rightImage || a == 2 && sideImage == leftImage; photoProgressViews[a].setProgress(loadProgress, animated); if (a == 0 && videoPlayer != null && videoPlayerSeekbar != null) { float bufferedProgress; if (currentVideoFinishedLoading) { bufferedProgress = 1.0f; } else { long newTime = SystemClock.elapsedRealtime(); if (Math.abs(newTime - lastBufferedPositionCheck) >= 500) { float progress; if (seekToProgressPending == 0) { long duration = videoPlayer.getDuration(); long position = videoPlayer.getCurrentPosition(); if (duration >= 0 && duration != C.TIME_UNSET && position >= 0) { progress = position / (float) duration; } else { progress = 0.0f; } } else { progress = seekToProgressPending; } bufferedProgress = isStreaming ? FileLoader.getInstance(currentAccount).getBufferedProgressFromPosition(progress, currentFileNames[0]) : 1.0f; lastBufferedPositionCheck = newTime; } else { bufferedProgress = -1; } } if (bufferedProgress != -1) { videoPlayerSeekbar.setBufferedProgress(bufferedProgress); if (pipVideoView != null) { pipVideoView.setBufferedProgress(bufferedProgress); } videoPlayerSeekbarView.invalidate(); } checkBufferedProgress(loadProgress); } } } } else if (id == NotificationCenter.dialogPhotosLoaded) { int guid = (Integer) args[3]; int did = (Integer) args[0]; if (avatarsDialogId == did && classGuid == guid) { boolean fromCache = (Boolean) args[2]; int setToImage = -1; ArrayList photos = (ArrayList) args[4]; 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.location.local_id && size.location.volume_id == currentFileLocation.location.volume_id) { setToImage = imagesArrLocations.size(); break; } } } if (photo.dc_id != 0) { sizeFull.location.dc_id = photo.dc_id; sizeFull.location.file_reference = photo.file_reference; } ImageLocation location = ImageLocation.getForPhoto(sizeFull, photo); if (location != null) { imagesArrLocations.add(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); } else { TLRPC.User user = null; TLRPC.Chat chat = null; if (avatarsDialogId > 0) { user = MessagesController.getInstance(currentAccount).getUser(avatarsDialogId); } else { chat = MessagesController.getInstance(currentAccount).getChat(-avatarsDialogId); } if (user != null || chat != null) { ImageLocation location; if (user != null) { location = ImageLocation.getForUser(user, true); } else { location = ImageLocation.getForChat(chat, true); } if (location != null) { imagesArrLocations.add(0, location); avatarsArr.add(0, new TLRPC.TL_photoEmpty()); imagesArrLocationsSizes.add(0, 0); setImageIndex(0); } } } if (fromCache) { MessagesController.getInstance(currentAccount).loadDialogPhotos(avatarsDialogId, 80, 0, false, classGuid); } } } else if (id == NotificationCenter.mediaCountDidLoad) { long uid = (Long) args[0]; if (uid == currentDialogId || uid == mergeDialogId) { if (uid == currentDialogId) { totalImagesCount = (Integer) args[1]; /*if ((Boolean) args[2]) { SharedMediaQuery.getMediaCount(currentDialogId, sharedMediaType, classGuid, false); }*/ } else if (uid == mergeDialogId) { totalImagesCountMerge = (Integer) args[1]; /*if ((Boolean) args[2]) { SharedMediaQuery.getMediaCount(mergeDialogId, sharedMediaType, classGuid, false); }*/ } if (needSearchImageInArr && isFirstLoading) { isFirstLoading = false; loadingMoreImages = true; MediaDataController.getInstance(currentAccount).loadMedia(currentDialogId, 20, 0, sharedMediaType, 1, 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.mediaDidLoad) { 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 arr = (ArrayList) 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].indexOfKey(message.getId()) < 0) { 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] = imagesByIdsTemp[a].clone(); imagesByIdsTemp[a].clear(); } imagesArrTemp.clear(); needSearchImageInArr = false; currentIndex = -1; if (foundIndex >= imagesArr.size()) { foundIndex = imagesArr.size() - 1; } setImageIndex(foundIndex); } 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) { MediaDataController.getInstance(currentAccount).loadMedia(loadIndex == 0 ? currentDialogId : mergeDialogId, 40, loadFromMaxId, sharedMediaType, 1, classGuid); } else { MediaDataController.getInstance(currentAccount).loadMedia(loadIndex == 0 ? currentDialogId : mergeDialogId, 40, loadFromMaxId, sharedMediaType, 1, classGuid); } } } } else { int added = 0; for (MessageObject message : arr) { if (imagesByIds[loadIndex].indexOfKey(message.getId()) < 0) { 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); } else { totalImagesCount = imagesArr.size(); totalImagesCountMerge = 0; } } } } } else if (id == NotificationCenter.emojiDidLoad) { if (captionTextViewSwitcher != null) { captionTextViewSwitcher.invalidateViews(); } } else if (id == NotificationCenter.filePreparingFailed) { MessageObject messageObject = (MessageObject) args[0]; if (loadInitialVideo) { loadInitialVideo = false; progressView.setVisibility(View.INVISIBLE); preparePlayer(currentPlayingVideoFile, false, false, currentSavedFilterState); } else if (tryStartRequestPreviewOnFinish) { releasePlayer(false); tryStartRequestPreviewOnFinish = !MediaController.getInstance().scheduleVideoConvert(videoPreviewMessageObject, true); } else if (messageObject == videoPreviewMessageObject) { requestingPreview = false; progressView.setVisibility(View.INVISIBLE); } } else if (id == NotificationCenter.fileNewChunkAvailable) { MessageObject messageObject = (MessageObject) args[0]; if (messageObject == videoPreviewMessageObject) { String finalPath = (String) args[1]; long finalSize = (Long) args[3]; float progress = (float) args[4]; photoProgressViews[0].setProgress(progress, true); if (finalSize != 0) { requestingPreview = false; photoProgressViews[0].setProgress(1f, true); photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, true); preparePlayer(Uri.fromFile(new File(finalPath)), false, true, currentSavedFilterState); } } } } private void showDownloadAlert() { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("NekoX", R.string.NekoX)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); boolean alreadyDownloading = currentMessageObject != null && currentMessageObject.isVideo() && FileLoader.getInstance(currentMessageObject.currentAccount).isLoadingFile(currentFileNames[0]); if (alreadyDownloading) { builder.setMessage(LocaleController.getString("PleaseStreamDownload", R.string.PleaseStreamDownload)); } else { builder.setMessage(LocaleController.getString("PleaseDownload", R.string.PleaseDownload)); } showAlertDialog(builder); } private void onScanPressed() { if (parentActivity == null) { 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; }*/ if (!TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath)) { f = new File(currentMessageObject.messageOwner.attachPath); if (!f.exists()) { f = null; } } if (f == null) { f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); } } else if (currentFileLocation != null) { f = FileLoader.getPathToAttach(currentFileLocation.location, avatarsDialogId != 0 || isEvent); } Bitmap bitmap; if (isVideo) { bitmap = videoTextureView.getBitmap(); } else if (f != null && f.exists()) { bitmap = ImageLoader.loadBitmap(f.getPath(), null, -1f, -1f, false); } else { showDownloadAlert(); return; } ProxyUtil.tryReadQR(parentActivity, bitmap); } catch (Exception ignored) { AlertUtil.showToast(LocaleController.getString("NoQrFound", R.string.NoQrFound)); } } 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; }*/ if (!TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath)) { f = new File(currentMessageObject.messageOwner.attachPath); if (!f.exists()) { f = null; } } if (f == null) { f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); } } else if (currentFileLocation != null) { f = FileLoader.getPathToAttach(currentFileLocation.location, avatarsDialogId != 0 || isEvent); } if (f.exists()) { Intent intent = new Intent(Intent.ACTION_SEND); if (isVideo) { intent.setType("video/mp4"); } else { if (currentMessageObject != null) { intent.setType(currentMessageObject.getMimeType()); } else { intent.setType("image/jpeg"); } } if (Build.VERSION.SDK_INT >= 24) { try { intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(parentActivity, BuildConfig.APPLICATION_ID + ".provider", f)); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } catch (Exception ignore) { intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f)); } } else { intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f)); } parentActivity.startActivityForResult(Intent.createChooser(intent, LocaleController.getString("ShareFile", R.string.ShareFile)), 500); } else { showDownloadAlert(); } } catch (Exception e) { FileLog.e(e); } } private void setScaleToFill() { float bitmapWidth = centerImage.getBitmapWidth(); float bitmapHeight = centerImage.getBitmapHeight(); if (bitmapWidth == 0 || bitmapHeight == 0) { return; } float containerWidth = getContainerViewWidth(); 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 setParentAlert(ChatAttachAlert alert) { parentAlert = alert; } public void setParentActivity(final Activity activity) { currentAccount = UserConfig.selectedAccount; centerImage.setCurrentAccount(currentAccount); leftImage.setCurrentAccount(currentAccount); rightImage.setCurrentAccount(currentAccount); if (parentActivity == activity || activity == null) { return; } parentActivity = activity; actvityContext = new ContextThemeWrapper(parentActivity, R.style.Theme_TMessages); touchSlop = ViewConfiguration.get(parentActivity).getScaledTouchSlop(); if (progressDrawables == null) { final Drawable circleDrawable = ContextCompat.getDrawable(parentActivity, R.drawable.circle_big); final CombinedDrawable playDrawable = new CombinedDrawable(circleDrawable.mutate(), ContextCompat.getDrawable(parentActivity, R.drawable.video_play1)); final CombinedDrawable pauseDrawable = new CombinedDrawable(circleDrawable.mutate(), ContextCompat.getDrawable(parentActivity, R.drawable.video_pause1)); progressDrawables = new Drawable[]{ circleDrawable, // PROGRESS_EMPTY ContextCompat.getDrawable(parentActivity, R.drawable.cancel_big), // PROGRESS_CANCEL ContextCompat.getDrawable(parentActivity, R.drawable.load_big), // PROGRESS_LOAD playDrawable, // PROGRESS_PLAY pauseDrawable // PROGRESS_PAUSE }; } 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 public boolean dispatchKeyEvent(KeyEvent event) { int keyCode = event.getKeyCode(); if (!muteVideo && isCurrentVideo && videoPlayer != null && event.getRepeatCount() == 0 && event.getAction() == KeyEvent.ACTION_DOWN && (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN)) { videoPlayer.setVolume(1.0f); } return super.dispatchKeyEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (videoPlayerControlVisible && isPlaying) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: AndroidUtilities.cancelRunOnUIThread(hideActionBarRunnable); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_POINTER_UP: scheduleActionBarHide(); break; } } return super.dispatchTouchEvent(ev); } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean result; try { result = super.drawChild(canvas, child, drawingTime); } catch (Throwable ignore) { result = false; } 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; } else { int insetBottom = insets.getStableInsetBottom(); if (insetBottom >= 0 && AndroidUtilities.statusBarHeight >= 0) { int newSize = heightSize - AndroidUtilities.statusBarHeight - insets.getStableInsetBottom(); if (newSize > 0 && newSize < 4096) { AndroidUtilities.displaySize.y = newSize; } } } heightSize -= insets.getSystemWindowInsetBottom(); } 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) { int x = 0; animatingImageView.layout(x, 0, x + animatingImageView.getMeasuredWidth(), animatingImageView.getMeasuredHeight()); containerView.layout(x, 0, x + containerView.getMeasuredWidth(), containerView.getMeasuredHeight()); wasLayout = true; if (changed) { if (!dontResetZoomOnFirstLayout) { scale = 1; translationX = 0; translationY = 0; updateMinMax(scale); } if (checkImageView != null) { checkImageView.post(() -> { LayoutParams layoutParams = (LayoutParams) checkImageView.getLayoutParams(); WindowManager manager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Activity.WINDOW_SERVICE); int rotation = manager.getDefaultDisplay().getRotation(); layoutParams.topMargin = (ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(34)) / 2 + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); checkImageView.setLayoutParams(layoutParams); layoutParams = (LayoutParams) photosCounterView.getLayoutParams(); layoutParams.topMargin = (ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(40)) / 2 + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); photosCounterView.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 protected void onDraw(Canvas canvas) { if (Build.VERSION.SDK_INT >= 21 && isVisible && lastInsets != null) { WindowInsets insets = (WindowInsets) lastInsets; if (animationInProgress == 1) { blackPaint.setAlpha((int) (255 * animatingImageView.getAnimationProgress())); } else if (animationInProgress == 3) { blackPaint.setAlpha((int) (255 * (1.0f - animatingImageView.getAnimationProgress()))); } else { blackPaint.setAlpha(255); } canvas.drawRect(0, getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight() + insets.getSystemWindowInsetBottom(), blackPaint); } } }; 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((v, insets) -> { if (AndroidUtilities.statusBarHeight != insets.getSystemWindowInsetTop()) { AndroidUtilities.statusBarHeight = insets.getSystemWindowInsetTop(); ((LaunchActivity) parentActivity).drawerLayoutContainer.requestLayout(); } WindowInsets oldInsets = (WindowInsets) lastInsets; lastInsets = insets; if (oldInsets == null || !oldInsets.toString().equals(insets.toString())) { if (animationInProgress == 1 || animationInProgress == 3) { animatingImageView.setTranslationX(animatingImageView.getTranslationX() - getLeftInset()); animationValues[0][2] = animatingImageView.getTranslationX(); } if (windowView != null) { windowView.requestLayout(); } } containerView.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0); if (actionBar != null) { AndroidUtilities.cancelRunOnUIThread(updateContainerFlagsRunnable); if (isVisible && animationInProgress == 0) { AndroidUtilities.runOnUIThread(updateContainerFlagsRunnable, 200); } } return insets.consumeSystemWindowInsets(); }); containerView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); } 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 >= 28) { windowLayoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; } if (Build.VERSION.SDK_INT >= 21) { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } else { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } paintingOverlay = new PaintingOverlay(parentActivity); containerView.addView(paintingOverlay, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); actionBar = new ActionBar(activity) { @Override public void setAlpha(float alpha) { super.setAlpha(alpha); containerView.invalidate(); } }; actionBar.setTitleColor(0xffffffff); actionBar.setSubtitleColor(0xffffffff); actionBar.setBackgroundColor(Theme.ACTION_BAR_PHOTO_VIEWER_COLOR); actionBar.setOccupyStatusBar(Build.VERSION.SDK_INT >= 21); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); 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) { if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && currentMessageObject.messageOwner.media.webpage != null && currentMessageObject.messageOwner.media.webpage.document == null) { TLObject fileLocation = getFileLocation(currentIndex, null); f = FileLoader.getPathToAttach(fileLocation, true); } else { f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); } } else if (currentFileLocation != null) { f = FileLoader.getPathToAttach(currentFileLocation.location, avatarsDialogId != 0 || isEvent); } if (f != null && f.exists()) { MediaController.saveFile(f.toString(), parentActivity, currentMessageObject != null && currentMessageObject.isVideo() ? 1 : 0, null, null); } else { showDownloadAlert(); } } else if (id == gallery_menu_scan) { onScanPressed(); } else if (id == gallery_menu_showall) { if (currentDialogId != 0) { disableShowCheck = true; Bundle args2 = new Bundle(); args2.putLong("dialog_id", currentDialogId); MediaActivity mediaActivity = new MediaActivity(args2, new int[]{-1, -1, -1, -1, -1, -1}, null, sharedMediaType); if (parentChatActivity != null) { mediaActivity.setChatInfo(parentChatActivity.getCurrentChatInfo()); } closePhoto(false, false); ((LaunchActivity) parentActivity).presentFragment(mediaActivity, false, true); } } else if (id == gallery_menu_showinchat) { if (currentMessageObject == null) { return; } Bundle args = new Bundle(); int lower_part = (int) currentDialogId; int high_id = (int) (currentDialogId >> 32); if (lower_part != 0) { if (lower_part > 0) { args.putInt("user_id", lower_part); } else if (lower_part < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_part); if (chat != null && chat.migrated_to != null) { args.putInt("migrated_to", lower_part); lower_part = -chat.migrated_to.channel_id; } args.putInt("chat_id", -lower_part); } } else { args.putInt("enc_id", high_id); } args.putInt("message_id", currentMessageObject.getId()); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); LaunchActivity launchActivity = (LaunchActivity) parentActivity; boolean remove = launchActivity.getMainFragmentsCount() > 1 || AndroidUtilities.isTablet(); launchActivity.presentFragment(new ChatActivity(args), remove, true); currentMessageObject = null; closePhoto(false, false); } else if (id == gallery_menu_send || id == gallery_menu_send_noquote) { if (currentMessageObject == null || parentActivity == null) { return; } ((LaunchActivity) parentActivity).switchToAccount(currentMessageObject.currentAccount, true); Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putInt("dialogsType", 3); DialogsActivity fragment = new DialogsActivity(args); final ArrayList fmessages = new ArrayList<>(); fmessages.add(currentMessageObject); fragment.setDelegate((fragment1, dids, message, param) -> { if (dids.size() > 1 || dids.get(0) == UserConfig.getInstance(currentAccount).getClientUserId() || message != null) { for (int a = 0; a < dids.size(); a++) { long did = dids.get(a); if (message != null) { SendMessagesHelper.getInstance(currentAccount).sendMessage(message.toString(), did, null, null, true, null, null, null, true, 0); } if (id == gallery_menu_send_noquote) { for (MessageObject object : fmessages) { SendMessagesHelper.getInstance(currentAccount).processForwardFromMyName(object, did, true, true, 0); } } else { SendMessagesHelper.getInstance(currentAccount).sendMessage(fmessages, did, true, 0); } } fragment1.finishFragment(); } else { long did = dids.get(0); int lower_part = (int) did; int high_part = (int) (did >> 32); Bundle args1 = new Bundle(); if (id == gallery_menu_send_noquote) { args1.putBoolean("forward_noquote", true); } args1.putBoolean("scrollToTopOnResume", true); if (lower_part != 0) { if (lower_part > 0) { args1.putInt("user_id", lower_part); } else if (lower_part < 0) { args1.putInt("chat_id", -lower_part); } } else { args1.putInt("enc_id", high_part); } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); ChatActivity chatActivity = new ChatActivity(args1); if (((LaunchActivity) parentActivity).presentFragment(chatActivity, true, false)) { chatActivity.showFieldPanelForForward(true, fmessages); } else { fragment1.finishFragment(); } } }); ((LaunchActivity) parentActivity).presentFragment(fragment, false, true); closePhoto(false, false); } else if (id == gallery_menu_delete) { if (parentActivity == null || placeProvider == null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); String text = placeProvider.getDeleteMessageString(); if (text != null) { builder.setTitle(LocaleController.getString("AreYouSureDeletePhotoTitle", R.string.AreYouSureDeletePhotoTitle)); builder.setMessage(text); } else if (currentMessageObject != null && currentMessageObject.isVideo()) { builder.setTitle(LocaleController.getString("AreYouSureDeleteVideoTitle", R.string.AreYouSureDeleteVideoTitle)); builder.setMessage(LocaleController.formatString("AreYouSureDeleteVideo", R.string.AreYouSureDeleteVideo)); } else if (currentMessageObject != null && currentMessageObject.isGif()) { builder.setTitle(LocaleController.getString("AreYouSureDeleteGIFTitle", R.string.AreYouSureDeleteGIFTitle)); builder.setMessage(LocaleController.formatString("AreYouSureDeleteGIF", R.string.AreYouSureDeleteGIF)); } else { builder.setTitle(LocaleController.getString("AreYouSureDeletePhotoTitle", R.string.AreYouSureDeletePhotoTitle)); builder.setMessage(LocaleController.formatString("AreYouSureDeletePhoto", R.string.AreYouSureDeletePhoto)); } final boolean[] deleteForAll = new boolean[1]; if (currentMessageObject != null && !currentMessageObject.scheduled) { int lower_id = (int) currentMessageObject.getDialogId(); if (lower_id != 0) { TLRPC.Chat currentChat; TLRPC.User currentUser; if (lower_id > 0) { currentUser = MessagesController.getInstance(currentAccount).getUser(lower_id); currentChat = null; } else { currentUser = null; currentChat = MessagesController.getInstance(currentAccount).getChat(-lower_id); } if (currentUser != null || !ChatObject.isChannel(currentChat)) { boolean hasOutgoing = false; int currentDate = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); int revokeTimeLimit; if (currentUser != null) { revokeTimeLimit = MessagesController.getInstance(currentAccount).revokeTimePmLimit; } else { revokeTimeLimit = MessagesController.getInstance(currentAccount).revokeTimeLimit; } if (currentUser != null && currentUser.id != UserConfig.getInstance(currentAccount).getClientUserId() || currentChat != null) { if ((currentMessageObject.messageOwner.action == null || currentMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty) && currentMessageObject.isOut() && (currentDate - currentMessageObject.messageOwner.date) <= revokeTimeLimit) { FrameLayout frameLayout = new FrameLayout(parentActivity); CheckBoxCell cell = new CheckBoxCell(parentActivity, 1); cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); if (currentChat != null) { cell.setText(LocaleController.getString("DeleteForAll", R.string.DeleteForAll), "", false, false); } else { cell.setText(LocaleController.formatString("DeleteForUser", R.string.DeleteForUser, UserObject.getFirstName(currentUser)), "", false, false); } cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); cell.setOnClickListener(v -> { CheckBoxCell cell1 = (CheckBoxCell) v; deleteForAll[0] = !deleteForAll[0]; cell1.setChecked(deleteForAll[0], true); }); builder.setView(frameLayout); } } } } } builder.setPositiveButton(LocaleController.getString("Delete", R.string.Delete), (dialogInterface, i) -> { if (!imagesArr.isEmpty()) { if (currentIndex < 0 || currentIndex >= imagesArr.size()) { return; } MessageObject obj = imagesArr.get(currentIndex); if (obj.isSent()) { closePhoto(false, false); ArrayList arr = new ArrayList<>(); if (slideshowMessageId != 0) { arr.add(slideshowMessageId); } else { arr.add(obj.getId()); } ArrayList 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(currentAccount).getEncryptedChat((int) (obj.getDialogId() >> 32)); } MessagesController.getInstance(currentAccount).deleteMessages(arr, random_ids, encryptedChat, obj.getDialogId(), obj.messageOwner.to_id.channel_id, deleteForAll[0], obj.scheduled); } } else if (!avatarsArr.isEmpty()) { if (currentIndex < 0 || currentIndex >= avatarsArr.size()) { return; } TLRPC.Photo photo = avatarsArr.get(currentIndex); ImageLocation 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.location.local_id && size.location.volume_id == currentUserAvatarLocation.location.volume_id) { current = true; break; } } } else if (currentLocation.location.local_id == currentUserAvatarLocation.location.local_id && currentLocation.location.volume_id == currentUserAvatarLocation.location.volume_id) { current = true; } } if (current) { MessagesController.getInstance(currentAccount).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; inputPhoto.file_reference = photo.file_reference; if (inputPhoto.file_reference == null) { inputPhoto.file_reference = new byte[0]; } MessagesController.getInstance(currentAccount).deleteUserPhoto(inputPhoto); MessagesStorage.getInstance(currentAccount).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); } } } else if (!secureDocuments.isEmpty()) { if (placeProvider == null) { return; } secureDocuments.remove(currentIndex); placeProvider.deleteImageAtIndex(currentIndex); if (secureDocuments.isEmpty()) { closePhoto(false, false); } else { int index = currentIndex; if (index >= secureDocuments.size()) { index = secureDocuments.size() - 1; } currentIndex = -1; setImageIndex(index); } } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); AlertDialog alertDialog = builder.create(); showAlertDialog(builder); TextView button = (TextView) alertDialog.getButton(DialogInterface.BUTTON_POSITIVE); if (button != null) { button.setTextColor(Theme.getColor(Theme.key_dialogTextRed2)); } } else if (id == gallery_menu_share) { onSharePressed(); } else if (id == gallery_menu_openin) { try { if (AndroidUtilities.openForView(currentMessageObject, parentActivity)) { closePhoto(false, false); } else { showDownloadAlert(); } } catch (Exception e) { FileLog.e(e); } } else if (id == gallery_menu_masks || id == gallery_menu_masks2) { if (parentActivity == null || currentMessageObject == null) { return; } TLObject object; if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { object = currentMessageObject.messageOwner.media.photo; } else if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { object = currentMessageObject.messageOwner.media.document; } else { return; } masksAlert = new StickersAlert(parentActivity, currentMessageObject, object) { @Override public void dismiss() { super.dismiss(); if (masksAlert == this) { masksAlert = null; } } }; masksAlert.show(); } else if (id == gallery_menu_pip) { if (pipItem.getAlpha() != 1.0f) { return; } switchToPip(); } else if (id == gallery_menu_cancel_loading) { if (currentMessageObject == null) { return; } FileLoader.getInstance(currentAccount).cancelLoadFile(currentMessageObject.getDocument()); releasePlayer(false); bottomLayout.setTag(1); bottomLayout.setVisibility(View.VISIBLE); } else if (id == gallery_menu_savegif) { if (currentMessageObject == null) { return; } TLRPC.Document document = currentMessageObject.getDocument(); if (parentChatActivity != null && parentChatActivity.chatActivityEnterView != null) { parentChatActivity.chatActivityEnterView.addRecentGif(document); } else { MediaDataController.getInstance(currentAccount).addRecentGif(document, (int) (System.currentTimeMillis() / 1000)); } MessagesController.getInstance(currentAccount).saveGif(currentMessageObject, document); } else if (id == gallery_menu_setascurrent) { if (!imagesArrLocations.isEmpty()) { if (currentIndex < 0 || currentIndex >= imagesArrLocations.size()) { return; } TLRPC.Photo photo = avatarsArr.get(currentIndex); TLRPC.TL_inputPhoto inputPhoto = new TLRPC.TL_inputPhoto(); inputPhoto.id = photo.id; inputPhoto.access_hash = photo.access_hash; inputPhoto.file_reference = photo.file_reference; if (inputPhoto.file_reference == null) { inputPhoto.file_reference = new byte[0]; } TLRPC.TL_photos_updateProfilePhoto req = new TLRPC.TL_photos_updateProfilePhoto(); req.id = inputPhoto; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (error == null) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); if (user == null) { user = UserConfig.getInstance(currentAccount).getCurrentUser(); if (user == null) { return; } MessagesController.getInstance(currentAccount).putUser(user, false); } else { UserConfig.getInstance(currentAccount).setCurrentUser(user); } MessagesStorage.getInstance(currentAccount).clearUserPhotos(user.id); ArrayList users = new ArrayList<>(); users.add(user); MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); } AndroidUtilities.runOnUIThread(() -> { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_ALL); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); UserConfig.getInstance(currentAccount).saveConfig(true); }); }); closePhoto(false, false); } } } @Override public boolean canOpenMenu() { if (currentMessageObject != null) { return true; } else if (currentFileLocation != null) { File f = FileLoader.getPathToAttach(getFileLocation(currentFileLocation), avatarsDialogId != 0 || isEvent); return f.exists(); } return false; } }); ActionBarMenu menu = actionBar.createMenu(); masksItem = menu.addItem(gallery_menu_masks, R.drawable.deproko_baseline_masks_24); pipItem = menu.addItem(gallery_menu_pip, R.drawable.ic_goinline); sendNoQuoteItem = menu.addItem(gallery_menu_send_noquote, R.drawable.msg_forward_noquote); sendItem = menu.addItem(gallery_menu_send, R.drawable.msg_forward); menuItem = menu.addItem(0, R.drawable.ic_ab_other); menuItem.addSubItem(gallery_menu_openin, R.drawable.baseline_open_in_browser_24, LocaleController.getString("OpenInExternalApp", R.string.OpenInExternalApp)).setColors(0xfffafafa, 0xfffafafa); menuItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); allMediaItem = menuItem.addSubItem(gallery_menu_showall, R.drawable.msg_media, LocaleController.getString("ShowAllMedia", R.string.ShowAllMedia)); allMediaItem.setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_savegif, R.drawable.deproko_baseline_gif_24, LocaleController.getString("SaveToGIFs", R.string.SaveToGIFs)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_showinchat, R.drawable.msg_message, LocaleController.getString("ShowInChat", R.string.ShowInChat)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_masks2, R.drawable.deproko_baseline_stickers_filled_24, LocaleController.getString("ShowStickers", R.string.ShowStickers)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_share, R.drawable.baseline_share_24, LocaleController.getString("ShareFile", R.string.ShareFile)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_save, R.drawable.baseline_image_24, LocaleController.getString("SaveToGallery", R.string.SaveToGallery)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_scan, R.drawable.wallet_qr, LocaleController.getString("ScanQRCode", R.string.ScanQRCode)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_setascurrent, R.drawable.deproko_baseline_camera_26, LocaleController.getString("SetAsCurrent", R.string.SetAsCurrent)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_delete, R.drawable.baseline_delete_24, LocaleController.getString("Delete", R.string.Delete)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_cancel_loading, R.drawable.baseline_cancel_24, LocaleController.getString("StopDownload", R.string.StopDownload)).setColors(0xfffafafa, 0xfffafafa); menuItem.redrawPopup(0xf9222222); sendNoQuoteItem.setContentDescription(LocaleController.getString("NoQuoteForward", R.string.NoQuoteForward)); sendItem.setContentDescription(LocaleController.getString("Forward", R.string.Forward)); menuItem.setSubMenuDelegate(new ActionBarMenuItem.ActionBarSubMenuItemDelegate() { @Override public void onShowSubMenu() { if (videoPlayerControlVisible && isPlaying) { AndroidUtilities.cancelRunOnUIThread(hideActionBarRunnable); } } @Override public void onHideSubMenu() { if (videoPlayerControlVisible && isPlaying) { scheduleActionBarHide(); } } }); bottomLayout = new FrameLayout(actvityContext); bottomLayout.setBackgroundColor(0x7f000000); containerView.addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); pressedDrawable[0] = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, new int[]{0x32000000, 0}); pressedDrawable[0].setShape(GradientDrawable.RECTANGLE); pressedDrawable[1] = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, new int[]{0x32000000, 0}); pressedDrawable[1].setShape(GradientDrawable.RECTANGLE); groupedPhotosListView = new GroupedPhotosListView(actvityContext, AndroidUtilities.dp(10)); containerView.addView(groupedPhotosListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 68, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 48)); groupedPhotosListView.setDelegate(new GroupedPhotosListView.GroupedPhotosListViewDelegate() { @Override public int getCurrentIndex() { return currentIndex; } @Override public int getCurrentAccount() { return currentAccount; } @Override public int getAvatarsDialogId() { return avatarsDialogId; } @Override public int getSlideshowMessageId() { return slideshowMessageId; } @Override public ArrayList getImagesArrLocations() { return imagesArrLocations; } @Override public ArrayList getImagesArr() { return imagesArr; } @Override public ArrayList getPageBlockArr() { return null; } @Override public Object getParentObject() { return null; } @Override public void setCurrentIndex(int index) { currentIndex = -1; if (currentThumb != null) { currentThumb.release(); currentThumb = null; } setImageIndex(index); } }); captionTextViewSwitcher = new CaptionTextViewSwitcher(containerView.getContext()); captionTextViewSwitcher.setFactory(this::createCaptionTextView); captionTextViewSwitcher.setVisibility(View.INVISIBLE); setCaptionHwLayerEnabled(true); for (int a = 0; a < 3; a++) { photoProgressViews[a] = new PhotoProgressView(containerView) { @Override protected void onBackgroundStateUpdated(int state) { if (this == photoProgressViews[0]) { updateAccessibilityOverlayVisibility(); } } @Override protected void onVisibilityChanged(boolean visible) { if (this == photoProgressViews[0]) { updateAccessibilityOverlayVisibility(); } } }; photoProgressViews[a].setBackgroundState(PROGRESS_EMPTY, false); } miniProgressView = new RadialProgressView(actvityContext) { @Override public void setAlpha(float alpha) { super.setAlpha(alpha); if (containerView != null) { containerView.invalidate(); } } @Override public void invalidate() { super.invalidate(); if (containerView != null) { containerView.invalidate(); } } }; miniProgressView.setUseSelfAlpha(true); miniProgressView.setProgressColor(0xffffffff); miniProgressView.setSize(AndroidUtilities.dp(54)); miniProgressView.setBackgroundResource(R.drawable.circle_big); miniProgressView.setVisibility(View.INVISIBLE); miniProgressView.setAlpha(0.0f); containerView.addView(miniProgressView, LayoutHelper.createFrame(64, 64, Gravity.CENTER)); shareButton = new ImageView(containerView.getContext()); shareButton.setImageResource(R.drawable.baseline_share_24); shareButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingIcon), PorterDuff.Mode.SRC_IN)); shareButton.setScaleType(ImageView.ScaleType.CENTER); shareButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); bottomLayout.addView(shareButton, LayoutHelper.createFrame(50, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); shareButton.setOnClickListener(v -> onSharePressed()); shareButton.setContentDescription(LocaleController.getString("ShareFile", R.string.ShareFile)); nameTextView = new FadingTextViewLayout(containerView.getContext()) { @Override protected void onTextViewCreated(TextView textView) { super.onTextViewCreated(textView); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); textView.setEllipsize(TextUtils.TruncateAt.END); textView.setTextColor(0xffffffff); textView.setGravity(Gravity.LEFT); } }; bottomLayout.addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 5, 60, 0)); dateTextView = new FadingTextViewLayout(containerView.getContext(), true) { private LocaleController.LocaleInfo lastLocaleInfo = null; private int staticCharsCount = 0; @Override protected void onTextViewCreated(TextView textView) { super.onTextViewCreated(textView); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); textView.setEllipsize(TextUtils.TruncateAt.END); textView.setTextColor(0xffffffff); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); textView.setGravity(Gravity.LEFT); } @Override protected int getStaticCharsCount() { final LocaleController.LocaleInfo localeInfo = LocaleController.getInstance().getCurrentLocaleInfo(); if (lastLocaleInfo != localeInfo) { lastLocaleInfo = localeInfo; staticCharsCount = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(new Date()), LocaleController.getInstance().formatterDay.format(new Date())).length(); } return staticCharsCount; } @Override public void setText(CharSequence text, boolean animated) { if (animated) { boolean dontAnimateUnchangedStaticChars = true; if (LocaleController.isRTL) { final int staticCharsCount = getStaticCharsCount(); if (staticCharsCount > 0) { if (text.length() != staticCharsCount || getText() == null || getText().length() != staticCharsCount) { dontAnimateUnchangedStaticChars = false; } } } setText(text, true, dontAnimateUnchangedStaticChars); } else { setText(text, false, false); } } }; bottomLayout.addView(dateTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 25, 50, 0)); createVideoControlsInterface(); progressView = new RadialProgressView(parentActivity); progressView.setProgressColor(0xffffffff); progressView.setBackgroundResource(R.drawable.circle_big); progressView.setVisibility(View.INVISIBLE); containerView.addView(progressView, LayoutHelper.createFrame(54, 54, Gravity.CENTER)); qualityPicker = new PickerBottomLayoutViewer(parentActivity); qualityPicker.setBackgroundColor(0x7f000000); qualityPicker.updateSelectedCount(0, false); qualityPicker.setTranslationY(AndroidUtilities.dp(120)); qualityPicker.doneButton.setText(LocaleController.getString("Done", R.string.Done).toUpperCase()); qualityPicker.doneButton.setTextColor(Theme.getColor(Theme.key_dialogFloatingButton)); containerView.addView(qualityPicker, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); qualityPicker.cancelButton.setOnClickListener(view -> { selectedCompression = previousCompression; didChangedCompressionLevel(false); showQualityView(false); requestVideoPreview(2); }); qualityPicker.doneButton.setOnClickListener(view -> { showQualityView(false); requestVideoPreview(2); }); videoForwardDrawable = new VideoForwardDrawable(); videoForwardDrawable.setDelegate(new VideoForwardDrawable.VideoForwardDrawableDelegate() { @Override public void onAnimationEnd() { } @Override public void invalidate() { containerView.invalidate(); } }); qualityChooseView = new QualityChooseView(parentActivity); qualityChooseView.setTranslationY(AndroidUtilities.dp(120)); qualityChooseView.setVisibility(View.INVISIBLE); qualityChooseView.setBackgroundColor(0x7f000000); containerView.addView(qualityChooseView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 70, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 48)); pickerView = new FrameLayout(actvityContext) { @Override public boolean dispatchTouchEvent(MotionEvent ev) { return bottomTouchEnabled && super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return bottomTouchEnabled && super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { return bottomTouchEnabled && super.onTouchEvent(event); } @Override public void setTranslationY(float translationY) { super.setTranslationY(translationY); if (videoTimelineView != null && videoTimelineView.getVisibility() != GONE) { videoTimelineView.setTranslationY(translationY); } } @Override public void setAlpha(float alpha) { super.setAlpha(alpha); if (videoTimelineView != null && videoTimelineView.getVisibility() != GONE) { videoTimelineView.setAlpha(alpha); } } @Override public void setVisibility(int visibility) { super.setVisibility(visibility); if (videoTimelineView != null && videoTimelineView.getVisibility() != GONE) { videoTimelineView.setVisibility(visibility == VISIBLE ? VISIBLE : INVISIBLE); } } }; pickerView.setBackgroundColor(0x7f000000); containerView.addView(pickerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT)); docNameTextView = new TextView(containerView.getContext()); docNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); docNameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); docNameTextView.setSingleLine(true); docNameTextView.setMaxLines(1); docNameTextView.setEllipsize(TextUtils.TruncateAt.END); docNameTextView.setTextColor(0xffffffff); docNameTextView.setGravity(Gravity.LEFT); pickerView.addView(docNameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 20, 23, 84, 0)); docInfoTextView = new TextView(containerView.getContext()); docInfoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); docInfoTextView.setSingleLine(true); docInfoTextView.setMaxLines(1); docInfoTextView.setEllipsize(TextUtils.TruncateAt.END); docInfoTextView.setTextColor(0xffffffff); docInfoTextView.setGravity(Gravity.LEFT); pickerView.addView(docInfoTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 20, 46, 84, 0)); videoTimelineView = new VideoTimelinePlayView(parentActivity); videoTimelineView.setDelegate(new VideoTimelinePlayView.VideoTimelineViewDelegate() { @Override public void onLeftProgressChanged(float progress) { if (videoPlayer == null) { return; } if (videoPlayer.isPlaying()) { videoPlayer.pause(); containerView.invalidate(); } videoPlayer.seekTo((int) (videoDuration * progress)); videoPlayerSeekbar.setProgress(0); videoTimelineView.setProgress(0); updateVideoInfo(); } @Override public void onRightProgressChanged(float progress) { if (videoPlayer == null) { return; } if (videoPlayer.isPlaying()) { videoPlayer.pause(); containerView.invalidate(); } videoPlayer.seekTo((int) (videoDuration * progress)); videoPlayerSeekbar.setProgress(1f); videoTimelineView.setProgress(1f); updateVideoInfo(); } @Override public void onPlayProgressChanged(float progress) { if (videoPlayer == null) { return; } videoPlayer.seekTo((int) (videoDuration * progress)); } @Override public void didStartDragging() { } @Override public void didStopDragging() { } }); videoTimelineView.setVisibility(View.GONE); videoTimelineView.setBackgroundColor(0x7f000000); containerView.addView(videoTimelineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 58, Gravity.LEFT | Gravity.BOTTOM, 0, 8, 0, 0)); pickerViewSendButton = new ImageView(parentActivity) { @Override public boolean dispatchTouchEvent(MotionEvent ev) { return bottomTouchEnabled && super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { return bottomTouchEnabled && super.onTouchEvent(event); } }; pickerViewSendButton.setScaleType(ImageView.ScaleType.CENTER); Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_dialogFloatingButton), Theme.getColor(Build.VERSION.SDK_INT >= 21 ? Theme.key_dialogFloatingButtonPressed : Theme.key_dialogFloatingButton)); pickerViewSendButton.setBackgroundDrawable(drawable); pickerViewSendButton.setColorFilter(new PorterDuffColorFilter(0xffffffff, PorterDuff.Mode.SRC_IN)); pickerViewSendButton.setImageResource(R.drawable.attach_send); pickerViewSendButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingIcon), PorterDuff.Mode.SRC_IN)); containerView.addView(pickerViewSendButton, LayoutHelper.createFrame(56, 56, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 14, 14)); pickerViewSendButton.setContentDescription(LocaleController.getString("Send", R.string.Send)); pickerViewSendButton.setOnClickListener(v -> { if (parentChatActivity != null && parentChatActivity.isInScheduleMode() && !parentChatActivity.isEditingMessageMedia()) { AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentChatActivity.getDialogId(), this::sendPressed); } else { sendPressed(true, 0); } }); pickerViewSendButton.setOnLongClickListener(view -> { if (parentChatActivity == null || parentChatActivity.isInScheduleMode()) { return false; } TLRPC.Chat chat = parentChatActivity.getCurrentChat(); TLRPC.User user = parentChatActivity.getCurrentUser(); if (parentChatActivity.getCurrentEncryptedChat() != null) { return false; } sendPopupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(parentActivity); sendPopupLayout.setAnimationEnabled(false); sendPopupLayout.setOnTouchListener((v, event) -> { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { v.getHitRect(hitRect); if (!hitRect.contains((int) event.getX(), (int) event.getY())) { sendPopupWindow.dismiss(); } } } return false; }); sendPopupLayout.setDispatchKeyEventListener(keyEvent -> { if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && keyEvent.getRepeatCount() == 0 && sendPopupWindow != null && sendPopupWindow.isShowing()) { sendPopupWindow.dismiss(); } }); sendPopupLayout.setShowedFromBotton(false); sendPopupLayout.setBackgroundColor(0xf9222222); int i = 0; for (int a = 0; a < 3; a++) { if (a == 1 && placeProvider != null && placeProvider.getSelectedPhotos() != null) { HashMap hashMap = placeProvider.getSelectedPhotos(); boolean hasTtl = false; for (HashMap.Entry entry : hashMap.entrySet()) { Object object = entry.getValue(); if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; if (photoEntry.ttl != 0) { hasTtl = true; break; } } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage searchImage = (MediaController.SearchImage) object; if (searchImage.ttl != 0) { hasTtl = true; break; } } } if (hasTtl) { continue; } } else if (a == 2 && UserObject.isUserSelf(user)) { continue; } int num = a; ActionBarMenuSubItem cell = new ActionBarMenuSubItem(parentActivity); cell.setBackgroundDrawable(Theme.createSelectorDrawable(0x24ffffff, 7)); if (num == 0) { cell.setTextAndIcon(LocaleController.getString("Translate", R.string.Translate), R.drawable.ic_translate); } else if (num == 1) { if (UserObject.isUserSelf(user)) { cell.setTextAndIcon(LocaleController.getString("SetReminder", R.string.SetReminder), R.drawable.baseline_date_range_24); } else { cell.setTextAndIcon(LocaleController.getString("ScheduleMessage", R.string.ScheduleMessage), R.drawable.baseline_date_range_24); } } else if (num == 2) { cell.setTextAndIcon(LocaleController.getString("SendWithoutSound", R.string.SendWithoutSound), R.drawable.input_notify_off); } cell.setMinimumWidth(AndroidUtilities.dp(196)); cell.setColors(0xffffffff, 0xffffffff); sendPopupLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 48 * i, 0, 0)); int chatId; if (chat != null) { chatId = chat.id; } else if (user != null) { chatId = user.id; } else { chatId = -1; } cell.setOnClickListener(v -> { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { sendPopupWindow.dismiss(); } if (num == 0) { translateComment(TranslateDb.getChatLanguage(chatId, TranslatorKt.getCode2Locale(NekoConfig.translateInputLang))); } else if (num == 1) { AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentChatActivity.getDialogId(), this::sendPressed); } else if (num == 1) { sendPressed(false, 0); } }); cell.setOnLongClickListener(v -> { if (num == 0) { Translator.showTargetLangSelect(cell, true, (locale) -> { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { sendPopupWindow.dismiss(); } translateComment(locale); TranslateDb.saveChatLanguage(chatId, locale); return Unit.INSTANCE; }); return true; } return false; }); i++; } sendPopupWindow = new ActionBarPopupWindow(sendPopupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); sendPopupWindow.setAnimationEnabled(false); sendPopupWindow.setAnimationStyle(R.style.PopupContextAnimation2); sendPopupWindow.setOutsideTouchable(true); sendPopupWindow.setClippingEnabled(true); sendPopupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); sendPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); sendPopupWindow.getContentView().setFocusableInTouchMode(true); sendPopupLayout.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); sendPopupWindow.setFocusable(true); int[] location = new int[2]; view.getLocationInWindow(location); sendPopupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, location[0] + view.getMeasuredWidth() - sendPopupLayout.getMeasuredWidth() + AndroidUtilities.dp(14), location[1] - sendPopupLayout.getMeasuredHeight() - AndroidUtilities.dp(18)); view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); return false; }); LinearLayout itemsLayout = new LinearLayout(parentActivity); itemsLayout.setOrientation(LinearLayout.HORIZONTAL); pickerView.addView(itemsLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 48, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 34, 0)); cropItem = new ImageView(parentActivity); cropItem.setScaleType(ImageView.ScaleType.CENTER); cropItem.setImageResource(R.drawable.photo_crop); cropItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); itemsLayout.addView(cropItem, LayoutHelper.createLinear(70, 48)); cropItem.setOnClickListener(v -> { if (captionEditText.getTag() != null) { return; } switchToEditMode(1); }); cropItem.setContentDescription(LocaleController.getString("CropImage", R.string.CropImage)); rotateItem = new ImageView(parentActivity); rotateItem.setScaleType(ImageView.ScaleType.CENTER); rotateItem.setImageResource(R.drawable.tool_rotate); rotateItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); itemsLayout.addView(rotateItem, LayoutHelper.createLinear(70, 48)); rotateItem.setOnClickListener(v -> { if (photoCropView == null) { return; } photoCropView.rotate(); }); rotateItem.setContentDescription(LocaleController.getString("AccDescrRotate", R.string.AccDescrRotate)); compressItem = new ImageView(parentActivity); compressItem.setTag(1); compressItem.setScaleType(ImageView.ScaleType.CENTER); compressItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); SharedPreferences preferences = MessagesController.getGlobalMainSettings(); selectedCompression = preferences.getInt("compress_video2", selectCompression()); int compressIconWidth; if (selectedCompression <= 1) { compressItem.setImageResource(R.drawable.video_quality1); compressIconWidth = 48; } else if (selectedCompression == 2) { compressItem.setImageResource(R.drawable.video_quality2); compressIconWidth = 64; } else { selectedCompression = compressionsCount - 1; compressItem.setImageResource(R.drawable.video_quality3); compressIconWidth = 64; } itemsLayout.addView(compressItem, LayoutHelper.createLinear(70, 48)); compressItem.setPadding(AndroidUtilities.dp(70 - compressIconWidth) / 2, 0, AndroidUtilities.dp(70 - compressIconWidth) / 2, 0); compressItem.setOnClickListener(v -> { if (captionEditText.getTag() != null || muteVideo) { return; } if (compressItem.getTag() == null) { if (videoConvertSupported) { if (tooltip == null) { tooltip = new Tooltip(activity, containerView, 0xcc111111, Color.WHITE); } tooltip.setText(LocaleController.getString("VideoQualityIsTooLow", R.string.VideoQualityIsTooLow)); tooltip.show(compressItem); } return; } showQualityView(true); requestVideoPreview(1); }); String[] compressionStrings = {"360", "480", "720", "1080"}; compressItem.setContentDescription(LocaleController.getString("AccDescrVideoQuality", R.string.AccDescrVideoQuality) + ", " + compressionStrings[Math.max(0, selectedCompression)]); paintItem = new ImageView(parentActivity); paintItem.setScaleType(ImageView.ScaleType.CENTER); paintItem.setImageResource(R.drawable.photo_paint); paintItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); itemsLayout.addView(paintItem, LayoutHelper.createLinear(70, 48)); paintItem.setOnClickListener(v -> { if (captionEditText.getTag() != null) { return; } if (isCurrentVideo) { if (!videoConvertSupported) { return; } if (videoTextureView instanceof VideoEditTextureView) { VideoEditTextureView textureView = (VideoEditTextureView) videoTextureView; if (textureView.getVideoWidth() <= 0 || textureView.getVideoHeight() <= 0) { return; } } else { return; } } switchToEditMode(3); }); paintItem.setContentDescription(LocaleController.getString("AccDescrPhotoEditor", R.string.AccDescrPhotoEditor)); muteItem = new ImageView(parentActivity); muteItem.setScaleType(ImageView.ScaleType.CENTER); muteItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); containerView.addView(muteItem, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 0, 0, 0)); muteItem.setOnClickListener(v -> { if (captionEditText.getTag() != null) { return; } muteVideo = !muteVideo; updateMuteButton(); updateVideoInfo(); if (muteVideo && !checkImageView.isChecked()) { checkImageView.callOnClick(); } else { Object object = imagesArrLocals.get(currentIndex); if (object instanceof MediaController.MediaEditState) { ((MediaController.MediaEditState) object).editedInfo = getCurrentVideoEditedInfo(); } } }); cameraItem = new ImageView(parentActivity); cameraItem.setScaleType(ImageView.ScaleType.CENTER); cameraItem.setImageResource(R.drawable.photo_add); cameraItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); cameraItem.setContentDescription(LocaleController.getString("AccDescrTakeMorePics", R.string.AccDescrTakeMorePics)); containerView.addView(cameraItem, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 16, 0)); cameraItem.setOnClickListener(v -> { if (placeProvider == null || captionEditText.getTag() != null) { return; } placeProvider.needAddMorePhotos(); closePhoto(true, false); }); tuneItem = new ImageView(parentActivity); tuneItem.setScaleType(ImageView.ScaleType.CENTER); tuneItem.setImageResource(R.drawable.photo_tools); tuneItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); itemsLayout.addView(tuneItem, LayoutHelper.createLinear(70, 48)); tuneItem.setOnClickListener(v -> { if (captionEditText.getTag() != null) { return; } if (isCurrentVideo) { if (!videoConvertSupported) { return; } if (videoTextureView instanceof VideoEditTextureView) { VideoEditTextureView textureView = (VideoEditTextureView) videoTextureView; if (textureView.getVideoWidth() <= 0 || textureView.getVideoHeight() <= 0) { return; } } else { return; } } switchToEditMode(2); }); tuneItem.setContentDescription(LocaleController.getString("AccDescrPhotoAdjust", R.string.AccDescrPhotoAdjust)); timeItem = new ImageView(parentActivity); timeItem.setScaleType(ImageView.ScaleType.CENTER); timeItem.setImageResource(R.drawable.photo_timer); timeItem.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); timeItem.setContentDescription(LocaleController.getString("SetTimer", R.string.SetTimer)); itemsLayout.addView(timeItem, LayoutHelper.createLinear(70, 48)); timeItem.setOnClickListener(v -> { if (parentActivity == null || captionEditText.getTag() != null) { return; } BottomSheet.Builder builder = new BottomSheet.Builder(parentActivity); builder.setUseHardwareLayer(false); LinearLayout linearLayout = new LinearLayout(parentActivity); linearLayout.setOrientation(LinearLayout.VERTICAL); builder.setCustomView(linearLayout); TextView titleView = new TextView(parentActivity); titleView.setLines(1); titleView.setSingleLine(true); titleView.setText(LocaleController.getString("MessageLifetime", R.string.MessageLifetime)); titleView.setTextColor(0xffffffff); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); titleView.setEllipsize(TextUtils.TruncateAt.MIDDLE); titleView.setPadding(AndroidUtilities.dp(21), AndroidUtilities.dp(8), AndroidUtilities.dp(21), AndroidUtilities.dp(4)); titleView.setGravity(Gravity.CENTER_VERTICAL); linearLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); titleView.setOnTouchListener((v13, event) -> true); titleView = new TextView(parentActivity); titleView.setText(isCurrentVideo ? LocaleController.getString("MessageLifetimeVideo", R.string.MessageLifetimeVideo) : LocaleController.getString("MessageLifetimePhoto", R.string.MessageLifetimePhoto)); titleView.setTextColor(0xff808080); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); titleView.setEllipsize(TextUtils.TruncateAt.MIDDLE); titleView.setPadding(AndroidUtilities.dp(21), 0, AndroidUtilities.dp(21), AndroidUtilities.dp(8)); titleView.setGravity(Gravity.CENTER_VERTICAL); linearLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); titleView.setOnTouchListener((v12, event) -> true); final BottomSheet bottomSheet = builder.create(); final NumberPicker numberPicker = new NumberPicker(parentActivity); numberPicker.setMinValue(0); numberPicker.setMaxValue(28); Object object = imagesArrLocals.get(currentIndex); int currentTTL; if (object instanceof MediaController.PhotoEntry) { currentTTL = ((MediaController.PhotoEntry) object).ttl; } else if (object instanceof MediaController.SearchImage) { currentTTL = ((MediaController.SearchImage) object).ttl; } else { currentTTL = 0; } if (currentTTL == 0) { SharedPreferences preferences1 = MessagesController.getGlobalMainSettings(); numberPicker.setValue(preferences1.getInt("self_destruct", 7)); } else { if (currentTTL >= 0 && currentTTL < 21) { numberPicker.setValue(currentTTL); } else { numberPicker.setValue(21 + currentTTL / 5 - 5); } } numberPicker.setTextColor(0xffffffff); numberPicker.setSelectorColor(0xff4d4d4d); numberPicker.setFormatter(value -> { if (value == 0) { return LocaleController.getString("ShortMessageLifetimeForever", R.string.ShortMessageLifetimeForever); } else if (value >= 1 && value < 21) { return LocaleController.formatTTLString(value); } else { return LocaleController.formatTTLString((value - 16) * 5); } }); linearLayout.addView(numberPicker, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); FrameLayout buttonsLayout = new FrameLayout(parentActivity) { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int count = getChildCount(); int width = right - left; for (int a = 0; a < count; a++) { View child = getChildAt(a); if ((Integer) child.getTag() == Dialog.BUTTON_POSITIVE) { child.layout(width - getPaddingRight() - child.getMeasuredWidth(), getPaddingTop(), width - getPaddingRight() + child.getMeasuredWidth(), getPaddingTop() + child.getMeasuredHeight()); } else if ((Integer) child.getTag() == Dialog.BUTTON_NEGATIVE) { int x = getPaddingLeft(); child.layout(x, getPaddingTop(), x + child.getMeasuredWidth(), getPaddingTop() + child.getMeasuredHeight()); } else { child.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + child.getMeasuredWidth(), getPaddingTop() + child.getMeasuredHeight()); } } } }; buttonsLayout.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); linearLayout.addView(buttonsLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 52)); TextView textView = new TextView(parentActivity); textView.setMinWidth(AndroidUtilities.dp(64)); textView.setTag(Dialog.BUTTON_POSITIVE); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); textView.setTextColor(Theme.getColor(Theme.key_dialogFloatingButton)); textView.setGravity(Gravity.CENTER); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); textView.setText(LocaleController.getString("Done", R.string.Done).toUpperCase()); textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable(0xff49bcf2)); textView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); buttonsLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 36, Gravity.TOP | Gravity.RIGHT)); textView.setOnClickListener(v1 -> { int value = numberPicker.getValue(); SharedPreferences preferences1 = MessagesController.getGlobalMainSettings(); SharedPreferences.Editor editor = preferences1.edit(); editor.putInt("self_destruct", value); editor.apply(); bottomSheet.dismiss(); int seconds; if (value >= 0 && value < 21) { seconds = value; } else { seconds = (value - 16) * 5; } Object object1 = imagesArrLocals.get(currentIndex); if (object1 instanceof MediaController.PhotoEntry) { ((MediaController.PhotoEntry) object1).ttl = seconds; } else if (object1 instanceof MediaController.SearchImage) { ((MediaController.SearchImage) object1).ttl = seconds; } timeItem.setColorFilter(seconds != 0 ? new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN) : null); if (!checkImageView.isChecked()) { checkImageView.callOnClick(); } }); textView = new TextView(parentActivity); textView.setMinWidth(AndroidUtilities.dp(64)); textView.setTag(Dialog.BUTTON_NEGATIVE); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); textView.setTextColor(0xffffffff); textView.setGravity(Gravity.CENTER); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); textView.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); textView.setBackgroundDrawable(Theme.getRoundRectSelectorDrawable(0xffffffff)); textView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); buttonsLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 36, Gravity.TOP | Gravity.RIGHT)); textView.setOnClickListener(v14 -> bottomSheet.dismiss()); bottomSheet.show(); bottomSheet.setBackgroundColor(0xff000000); }); 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(view -> switchToEditMode(0)); editorDoneLayout.doneButton.setOnClickListener(view -> { if (currentEditMode == 1 && !photoCropView.isReady()) { return; } applyCurrentEditMode(); switchToEditMode(0); }); resetButton = new TextView(actvityContext); resetButton.setVisibility(View.GONE); resetButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); resetButton.setTextColor(0xffffffff); resetButton.setGravity(Gravity.CENTER); resetButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR, 0)); resetButton.setPadding(AndroidUtilities.dp(20), 0, AndroidUtilities.dp(20), 0); resetButton.setText(LocaleController.getString("Reset", R.string.CropReset).toUpperCase()); resetButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); editorDoneLayout.addView(resetButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.CENTER)); resetButton.setOnClickListener(v -> photoCropView.reset()); gestureDetector = new GestureDetector2(containerView.getContext(), this); gestureDetector.setIsLongpressEnabled(false); setDoubleTapEnabled(true); ImageReceiver.ImageReceiverDelegate imageReceiverDelegate = (imageReceiver, set, thumb, memCache) -> { if (imageReceiver == centerImage && set && !thumb) { if ((currentEditMode == 1 || sendPhotoType == SELECT_TYPE_AVATAR) && photoCropView != null) { Bitmap bitmap = imageReceiver.getBitmap(); if (bitmap != null) { photoCropView.setBitmap(bitmap, imageReceiver.getOrientation(), sendPhotoType != SELECT_TYPE_AVATAR, true, paintingOverlay); } } if (paintingOverlay.getVisibility() == View.VISIBLE) { containerView.requestLayout(); } } if (imageReceiver == centerImage && set && placeProvider != null && placeProvider.scaleToFill() && !ignoreDidSetImage) { 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) { @Override public boolean onTouchEvent(MotionEvent event) { return bottomTouchEnabled && super.onTouchEvent(event); } }; checkImageView.setDrawBackground(true); checkImageView.setHasBorder(true); checkImageView.setSize(34); checkImageView.setCheckOffset(AndroidUtilities.dp(1)); checkImageView.setColor(Theme.getColor(Theme.key_dialogFloatingButton), 0xffffffff); checkImageView.setVisibility(View.GONE); containerView.addView(checkImageView, LayoutHelper.createFrame(34, 34, Gravity.RIGHT | Gravity.TOP, 0, rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90 ? 61 : 71, 11, 0)); if (Build.VERSION.SDK_INT >= 21) { ((FrameLayout.LayoutParams) checkImageView.getLayoutParams()).topMargin += AndroidUtilities.statusBarHeight; } checkImageView.setOnClickListener(v -> { if (captionEditText.getTag() != null) { return; } setPhotoChecked(); }); photosCounterView = new CounterView(parentActivity); containerView.addView(photosCounterView, LayoutHelper.createFrame(40, 40, Gravity.RIGHT | Gravity.TOP, 0, rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90 ? 58 : 68, 64, 0)); if (Build.VERSION.SDK_INT >= 21) { ((FrameLayout.LayoutParams) photosCounterView.getLayoutParams()).topMargin += AndroidUtilities.statusBarHeight; } photosCounterView.setOnClickListener(v -> { if (captionEditText.getTag() != null || placeProvider == null || placeProvider.getSelectedPhotosOrder() == null || placeProvider.getSelectedPhotosOrder().isEmpty()) { return; } togglePhotosListView(!isPhotosListViewVisible, true); }); selectedPhotosListView = new SelectedPhotosListView(parentActivity); selectedPhotosListView.setVisibility(View.GONE); selectedPhotosListView.setAlpha(0.0f); selectedPhotosListView.setLayoutManager(new LinearLayoutManager(parentActivity, LinearLayoutManager.HORIZONTAL, true) { @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { LinearSmoothScrollerEnd linearSmoothScroller = new LinearSmoothScrollerEnd(recyclerView.getContext()) { @Override protected int calculateTimeForDeceleration(int dx) { return Math.max(180, super.calculateTimeForDeceleration(dx)); } }; linearSmoothScroller.setTargetPosition(position); startSmoothScroll(linearSmoothScroller); } }); selectedPhotosListView.setAdapter(selectedPhotosAdapter = new ListAdapter(parentActivity)); containerView.addView(selectedPhotosListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 103, Gravity.LEFT | Gravity.TOP)); selectedPhotosListView.setOnItemClickListener((view, position) -> { if (!imagesArrLocals.isEmpty() && currentIndex >= 0 && currentIndex < imagesArrLocals.size()) { Object entry = imagesArrLocals.get(currentIndex); if (entry instanceof MediaController.MediaEditState) { ((MediaController.MediaEditState) entry).editedInfo = getCurrentVideoEditedInfo(); } } ignoreDidSetImage = true; int idx = imagesArrLocals.indexOf(view.getTag()); if (idx >= 0) { currentIndex = -1; setImageIndex(idx); } ignoreDidSetImage = false; }); captionEditText = new PhotoViewerCaptionEnterView(actvityContext, containerView, windowView) { @Override public boolean dispatchTouchEvent(MotionEvent ev) { try { return !bottomTouchEnabled && super.dispatchTouchEvent(ev); } catch (Exception e) { FileLog.e(e); } return false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { return !bottomTouchEnabled && super.onInterceptTouchEvent(ev); } catch (Exception e) { FileLog.e(e); } return false; } @Override public boolean onTouchEvent(MotionEvent event) { return !bottomTouchEnabled && super.onTouchEvent(event); } @Override protected void extendActionMode(ActionMode actionMode, Menu menu) { if (parentChatActivity != null) { parentChatActivity.extendActionMode(menu); } } }; 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, false); } } @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); } } } }); if (Build.VERSION.SDK_INT >= 19) { captionEditText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); } containerView.addView(captionEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT)); mentionListView = new RecyclerListView(actvityContext) { @Override public boolean dispatchTouchEvent(MotionEvent ev) { return !bottomTouchEnabled && super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return !bottomTouchEnabled && super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { return !bottomTouchEnabled && super.onTouchEvent(event); } }; 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(RecyclerListView.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, View.ALPHA, 0.0f, 1.0f) ); mentionListAnimation.addListener(new AnimatorListenerAdapter() { @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, View.ALPHA, 0.0f) ); mentionListAnimation.addListener(new AnimatorListenerAdapter() { @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) { } })); mentionListView.setOnItemClickListener((view, 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.username != null) { captionEditText.replaceWithText(start, len, "@" + user.username + " ", false); } else { String name = UserObject.getFirstName(user); Spannable spannable = new SpannableString(name + " "); spannable.setSpan(new URLSpanUserMentionPhotoViewer("" + user.id, true), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); captionEditText.replaceWithText(start, len, spannable, false); } } else if (object instanceof String) { captionEditText.replaceWithText(start, len, object + " ", false); } else if (object instanceof MediaDataController.KeywordResult) { String code = ((MediaDataController.KeywordResult) object).emoji; captionEditText.addEmojiToRecent(code); captionEditText.replaceWithText(start, len, code, true); } }); mentionListView.setOnItemLongClickListener((view, position) -> { Object object = mentionsAdapter.getItem(position); int start = mentionsAdapter.getResultStartPosition(); int len = mentionsAdapter.getResultLength(); if (object instanceof String) { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("NekoX", R.string.NekoX)); builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), (dialogInterface, i) -> mentionsAdapter.clearRecentHashtags()); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showAlertDialog(builder); return true; } else if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; String name = UserObject.getFirstName(user); Spannable spannable = new SpannableString("@" + name + " "); spannable.setSpan(new URLSpanUserMentionPhotoViewer("" + user.id, true), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); captionEditText.replaceWithText(start, len, spannable, false); return true; } return false; }); AccessibilityManager am = (AccessibilityManager) actvityContext.getSystemService(Context.ACCESSIBILITY_SERVICE); if (am.isEnabled()) { playButtonAccessibilityOverlay = new View(actvityContext); playButtonAccessibilityOverlay.setContentDescription(LocaleController.getString("AccActionPlay", R.string.AccActionPlay)); playButtonAccessibilityOverlay.setFocusable(true); containerView.addView(playButtonAccessibilityOverlay, LayoutHelper.createFrame(64, 64, Gravity.CENTER)); } } private void translateComment(Locale target) { String origin = captionEditText.getFieldCharSequence().toString(); TranslateDb db = TranslateDb.forLocale(target); if (db.contains(origin)) { String translated = db.query(origin); captionEditText.setFieldText(translated); return; } Translator.translate(target, origin, new Translator.Companion.TranslateCallBack() { final AtomicBoolean cancel = new AtomicBoolean(); AlertDialog status = AlertUtil.showProgress(parentActivity); { status.setOnCancelListener((__) -> { cancel.set(true); }); status.show(); } @Override public void onSuccess(@NotNull String translation) { status.dismiss(); captionEditText.setFieldText(translation); } @Override public void onFailed(boolean unsupported, @NotNull String message) { status.dismiss(); AlertUtil.showTransFailedDialog(parentActivity, unsupported, message, () -> { status = AlertUtil.showProgress(parentActivity); status.show(); Translator.translate(origin, this); }); } }); } private void sendPressed(boolean notify, int scheduleDate) { if (captionEditText.getTag() != null) { return; } if (sendPhotoType == SELECT_TYPE_AVATAR) { applyCurrentEditMode(); } if (placeProvider != null && !doneButtonPressed) { if (parentChatActivity != null) { TLRPC.Chat chat = parentChatActivity.getCurrentChat(); TLRPC.User user = parentChatActivity.getCurrentUser(); if (user != null || ChatObject.isChannel(chat) && chat.megagroup || !ChatObject.isChannel(chat)) { MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("silent_" + parentChatActivity.getDialogId(), !notify).apply(); } } VideoEditedInfo videoEditedInfo = getCurrentVideoEditedInfo(); if (!imagesArrLocals.isEmpty() && currentIndex >= 0 && currentIndex < imagesArrLocals.size()) { Object entry = imagesArrLocals.get(currentIndex); if (entry instanceof MediaController.MediaEditState) { ((MediaController.MediaEditState) entry).editedInfo = videoEditedInfo; } } placeProvider.sendButtonPressed(currentIndex, videoEditedInfo, notify, scheduleDate); doneButtonPressed = true; closePhoto(false, false); } } private boolean checkInlinePermissions() { if (parentActivity == null) { return false; } if (Build.VERSION.SDK_INT < 23 || Settings.canDrawOverlays(parentActivity)) { return true; } else { new AlertDialog.Builder(parentActivity).setTitle(LocaleController.getString("AppName", R.string.AppName)) .setMessage(LocaleController.getString("PermissionDrawAboveOtherApps", R.string.PermissionDrawAboveOtherApps)) .setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialog, which) -> { if (parentActivity != null) { try { parentActivity.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + parentActivity.getPackageName()))); } catch (Exception e) { FileLog.e(e); } } }).show(); } return false; } private View.OnClickListener openCaptionEnter = (v) -> { if (!needCaptionLayout) { return; } openCaptionEnter(); }; private TextView createCaptionTextView() { TextView textView = new TextView(actvityContext) { @Override public boolean onTouchEvent(MotionEvent event) { boolean b = super.onTouchEvent(event); return bottomTouchEnabled && b; } @Override public void scrollTo(int x, int y) { if (getParent().getParent() == pickerView) { super.scrollTo(x, y); setOnClickListener(null); } } }; textView.setMovementMethod(new LinkMovementMethodMy()); textView.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(8), AndroidUtilities.dp(16), AndroidUtilities.dp(8)); textView.setLinkTextColor(0xff76c2f1); textView.setTextColor(0xffffffff); textView.setHighlightColor(0x33ffffff); textView.setGravity(Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); textView.setOnClickListener(openCaptionEnter); return textView; } private int getLeftInset() { if (lastInsets != null && Build.VERSION.SDK_INT >= 21) { return ((WindowInsets) lastInsets).getSystemWindowInsetLeft(); } return 0; } private int getRightInset() { if (lastInsets != null && Build.VERSION.SDK_INT >= 21) { return ((WindowInsets) lastInsets).getSystemWindowInsetRight(); } return 0; } private void dismissInternal() { try { if (windowView.getParent() != null) { ((LaunchActivity) parentActivity).drawerLayoutContainer.setAllowDrawContent(true); WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); wm.removeView(windowView); } } catch (Exception e) { FileLog.e(e); } } private void switchToPip() { if (videoPlayer == null || !textureUploaded || !checkInlinePermissions() || changingTextureView || switchingInlineMode || isInline) { return; } if (PipInstance != null) { PipInstance.destroyPhotoViewer(); } openedFullScreenVideo = false; PipInstance = Instance; Instance = null; switchingInlineMode = true; isVisible = false; if (currentPlaceObject != null) { currentPlaceObject.imageReceiver.setVisible(true, true); AnimatedFileDrawable animation = currentPlaceObject.imageReceiver.getAnimation(); if (animation != null) { Bitmap bitmap = animation.getAnimatedBitmap(); if (bitmap != null) { try { Bitmap src = videoTextureView.getBitmap(bitmap.getWidth(), bitmap.getHeight()); Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(src, 0, 0, null); src.recycle(); } catch (Throwable e) { FileLog.e(e); } } animation.seekTo(videoPlayer.getCurrentPosition(), true); currentPlaceObject.imageReceiver.setAllowStartAnimation(true); currentPlaceObject.imageReceiver.startAnimation(); } } if (Build.VERSION.SDK_INT >= 21) { pipAnimationInProgress = true; org.telegram.ui.Components.Rect rect = PipVideoView.getPipRect(aspectRatioFrameLayout.getAspectRatio()); float scale = rect.width / videoTextureView.getWidth(); rect.y += AndroidUtilities.statusBarHeight; AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( ObjectAnimator.ofFloat(textureImageView, View.SCALE_X, scale), ObjectAnimator.ofFloat(textureImageView, View.SCALE_Y, scale), ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_X, rect.x), ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_Y, rect.y), ObjectAnimator.ofFloat(videoTextureView, View.SCALE_X, scale), ObjectAnimator.ofFloat(videoTextureView, View.SCALE_Y, scale), ObjectAnimator.ofFloat(videoTextureView, View.TRANSLATION_X, rect.x - aspectRatioFrameLayout.getX() + getLeftInset()), ObjectAnimator.ofFloat(videoTextureView, View.TRANSLATION_Y, rect.y - aspectRatioFrameLayout.getY()), ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0), ObjectAnimator.ofFloat(actionBar, View.ALPHA, 0.0f), ObjectAnimator.ofFloat(bottomLayout, View.ALPHA, 0.0f), ObjectAnimator.ofFloat(captionTextViewSwitcher, View.ALPHA, 0.0f), ObjectAnimator.ofFloat(groupedPhotosListView, View.ALPHA, 0.0f) ); animatorSet.setInterpolator(new DecelerateInterpolator()); animatorSet.setDuration(250); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { pipAnimationInProgress = false; switchToInlineRunnable.run(); } }); animatorSet.start(); } else { switchToInlineRunnable.run(); dismissInternal(); } } public VideoPlayer getVideoPlayer() { return videoPlayer; } public void exitFromPip() { if (!isInline) { return; } if (Instance != null) { Instance.closePhoto(false, true); } Instance = PipInstance; PipInstance = null; switchingInlineMode = true; if (currentBitmap != null) { currentBitmap.recycle(); currentBitmap = null; } changingTextureView = true; isInline = false; videoTextureView.setVisibility(View.INVISIBLE); aspectRatioFrameLayout.addView(videoTextureView); if (ApplicationLoader.mainInterfacePaused) { try { parentActivity.startService(new Intent(ApplicationLoader.applicationContext, BringAppForegroundService.class)); } catch (Throwable e) { FileLog.e(e); } } if (Build.VERSION.SDK_INT >= 21) { pipAnimationInProgress = true; org.telegram.ui.Components.Rect rect = PipVideoView.getPipRect(aspectRatioFrameLayout.getAspectRatio()); float scale = rect.width / textureImageView.getLayoutParams().width; rect.y += AndroidUtilities.statusBarHeight; textureImageView.setScaleX(scale); textureImageView.setScaleY(scale); textureImageView.setTranslationX(rect.x); textureImageView.setTranslationY(rect.y); videoTextureView.setScaleX(scale); videoTextureView.setScaleY(scale); videoTextureView.setTranslationX(rect.x - aspectRatioFrameLayout.getX()); videoTextureView.setTranslationY(rect.y - aspectRatioFrameLayout.getY()); } else { pipVideoView.close(); pipVideoView = null; } try { isVisible = true; WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); wm.addView(windowView, windowLayoutParams); if (currentPlaceObject != null) { currentPlaceObject.imageReceiver.setVisible(false, false); } } catch (Exception e) { FileLog.e(e); } if (Build.VERSION.SDK_INT >= 21) { waitingForDraw = 4; } } private void updateVideoSeekPreviewPosition() { int x = videoPlayerSeekbar.getThumbX() + AndroidUtilities.dp(2) - videoPreviewFrame.getMeasuredWidth() / 2; int min = AndroidUtilities.dp(10); int max = videoPlayerControlFrameLayout.getMeasuredWidth() - AndroidUtilities.dp(10) - videoPreviewFrame.getMeasuredWidth() / 2; if (x < min) { x = min; } else if (x >= max) { x = max; } videoPreviewFrame.setTranslationX(x); } private void showVideoSeekPreviewPosition(boolean show) { if (show && videoPreviewFrame.getTag() != null || !show && videoPreviewFrame.getTag() == null) { return; } if (show && !videoPreviewFrame.isReady()) { needShowOnReady = show; return; } if (videoPreviewFrameAnimation != null) { videoPreviewFrameAnimation.cancel(); } videoPreviewFrame.setTag(show ? 1 : null); videoPreviewFrameAnimation = new AnimatorSet(); videoPreviewFrameAnimation.playTogether(ObjectAnimator.ofFloat(videoPreviewFrame, View.ALPHA, show ? 1.0f : 0.0f)); videoPreviewFrameAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { videoPreviewFrameAnimation = null; } }); videoPreviewFrameAnimation.setDuration(180); videoPreviewFrameAnimation.start(); } private void createVideoControlsInterface() { videoPlayerControlFrameLayout = new VideoPlayerControlFrameLayout(containerView.getContext()); containerView.addView(videoPlayerControlFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); videoPlayerSeekbarView = new View(containerView.getContext()) { @Override protected void onDraw(Canvas canvas) { videoPlayerSeekbar.draw(canvas); } }; videoPlayerControlFrameLayout.addView(videoPlayerSeekbarView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); videoPlayerSeekbar = new VideoPlayerSeekBar(videoPlayerSeekbarView); videoPlayerSeekbar.setHorizontalPadding(AndroidUtilities.dp(2)); videoPlayerSeekbar.setColors(0x33ffffff, 0x33ffffff, Color.WHITE, Color.WHITE, Color.WHITE, 0x59ffffff); videoPlayerSeekbar.setDelegate(new VideoPlayerSeekBar.SeekBarDelegate() { @Override public void onSeekBarDrag(float progress) { if (videoPlayer != null) { if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { progress = videoTimelineView.getLeftProgress() + (videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()) * progress; } long duration = videoPlayer.getDuration(); if (duration == C.TIME_UNSET) { seekToProgressPending = progress; } else { videoPlayer.seekTo((int) (progress * duration)); } showVideoSeekPreviewPosition(false); needShowOnReady = false; } } @Override public void onSeekBarContinuousDrag(float progress) { if (videoPlayer != null && videoPreviewFrame != null) { videoPreviewFrame.setProgress(progress, videoPlayerSeekbar.getWidth()); } showVideoSeekPreviewPosition(true); updateVideoSeekPreviewPosition(); } }); videoPreviewFrame = new VideoSeekPreviewImage(containerView.getContext(), () -> { if (needShowOnReady) { showVideoSeekPreviewPosition(true); } }) { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); updateVideoSeekPreviewPosition(); } @Override public void setVisibility(int visibility) { super.setVisibility(visibility); if (visibility == VISIBLE) { updateVideoSeekPreviewPosition(); } } }; videoPreviewFrame.setAlpha(0.0f); containerView.addView(videoPreviewFrame, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 48 + 10)); videoPlayerTime = new SimpleTextView(containerView.getContext()); videoPlayerTime.setTextColor(0xffffffff); videoPlayerTime.setGravity(Gravity.RIGHT | Gravity.TOP); videoPlayerTime.setTextSize(14); videoPlayerControlFrameLayout.addView(videoPlayerTime, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT | Gravity.TOP, 0, 15, 12, 0)); } private void openCaptionEnter() { if (imageMoveAnimation != null || changeModeAnimation != null || currentEditMode != 0 || sendPhotoType == SELECT_TYPE_AVATAR || sendPhotoType == SELECT_TYPE_WALLPAPER || sendPhotoType == SELECT_TYPE_QR) { return; } selectedPhotosListView.setVisibility(View.GONE); selectedPhotosListView.setEnabled(false); selectedPhotosListView.setAlpha(0.0f); selectedPhotosListView.setTranslationY(-AndroidUtilities.dp(10)); photosCounterView.setRotationX(0.0f); isPhotosListViewVisible = false; captionEditText.setTag(1); captionEditText.openKeyboard(); captionEditText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); lastTitle = actionBar.getTitle(); if (isCurrentVideo) { actionBar.setTitle(muteVideo ? LocaleController.getString("GifCaption", R.string.GifCaption) : LocaleController.getString("VideoCaption", R.string.VideoCaption)); actionBar.setSubtitle(null); } else { actionBar.setTitle(LocaleController.getString("PhotoCaption", R.string.PhotoCaption)); } } private VideoEditedInfo getCurrentVideoEditedInfo() { if (!isCurrentVideo && hasAnimatedMediaEntities() && centerImage.getBitmapWidth() > 0) { VideoEditedInfo videoEditedInfo = new VideoEditedInfo(); videoEditedInfo.start = videoEditedInfo.startTime = 0; videoEditedInfo.endTime = Math.min(3000, currentAverageDuration); while (videoEditedInfo.endTime > 0 && videoEditedInfo.endTime < 1000) { videoEditedInfo.endTime *= 2; } videoEditedInfo.end = videoEditedInfo.endTime; videoEditedInfo.rotationValue = 0; videoEditedInfo.originalPath = currentImagePath; videoEditedInfo.estimatedSize = (int) (videoEditedInfo.endTime / 1000.0f * 115200); videoEditedInfo.estimatedDuration = videoEditedInfo.endTime; videoEditedInfo.framerate = 30; videoEditedInfo.originalDuration = videoEditedInfo.endTime; videoEditedInfo.filterState = currentSavedFilterState; videoEditedInfo.paintPath = currentPaintPath; videoEditedInfo.mediaEntities = currentMediaEntities; videoEditedInfo.isPhoto = true; int width = centerImage.getBitmapWidth(); int height = centerImage.getBitmapHeight(); float scale = Math.max(width / 854.0f, height / 854.0f); if (scale < 1) { scale = 1; } width /= scale; height /= scale; if (width % 16 != 0) { width = Math.round(width / 16.0f) * 16; } if (height % 16 != 0) { height = Math.round(height / 16.0f) * 16; } videoEditedInfo.originalWidth = videoEditedInfo.resultWidth = width; videoEditedInfo.originalHeight = videoEditedInfo.resultHeight = height; videoEditedInfo.bitrate = -1; videoEditedInfo.muted = true; return videoEditedInfo; } if (!isCurrentVideo || currentPlayingVideoFile == null || compressionsCount == 0) { return null; } VideoEditedInfo videoEditedInfo = new VideoEditedInfo(); videoEditedInfo.startTime = startTime; videoEditedInfo.endTime = endTime; videoEditedInfo.start = videoCutStart; videoEditedInfo.end = videoCutEnd; videoEditedInfo.rotationValue = rotationValue; videoEditedInfo.originalWidth = originalWidth; videoEditedInfo.originalHeight = originalHeight; videoEditedInfo.bitrate = bitrate; videoEditedInfo.originalPath = currentPathObject; videoEditedInfo.estimatedSize = estimatedSize != 0 ? estimatedSize : 1; videoEditedInfo.estimatedDuration = estimatedDuration; videoEditedInfo.framerate = videoFramerate; videoEditedInfo.originalDuration = (long) (videoDuration * 1000); videoEditedInfo.filterState = currentSavedFilterState; videoEditedInfo.paintPath = currentPaintPath; videoEditedInfo.mediaEntities = currentMediaEntities != null && !currentMediaEntities.isEmpty() ? currentMediaEntities : null; if (!muteVideo && (compressItem.getTag() == null || (videoEditedInfo.resultWidth == originalWidth && videoEditedInfo.resultHeight == originalHeight))) { videoEditedInfo.resultWidth = originalWidth; videoEditedInfo.resultHeight = originalHeight; videoEditedInfo.bitrate = muteVideo ? -1 : originalBitrate; videoEditedInfo.muted = muteVideo; } else { if (muteVideo) { selectedCompression = 1; updateWidthHeightBitrateForCompression(); } videoEditedInfo.resultWidth = resultWidth; videoEditedInfo.resultHeight = resultHeight; videoEditedInfo.bitrate = muteVideo ? -1 : bitrate; videoEditedInfo.muted = muteVideo; } return videoEditedInfo; } private boolean supportsSendingNewEntities() { return parentChatActivity != null && (parentChatActivity.currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(parentChatActivity.currentEncryptedChat.layer) >= 101); } private void closeCaptionEnter(boolean apply) { if (currentIndex < 0 || currentIndex >= imagesArrLocals.size()) { return; } Object object = imagesArrLocals.get(currentIndex); if (apply) { CharSequence caption = captionEditText.getFieldCharSequence(); CharSequence[] result = new CharSequence[]{caption}; ArrayList entities = MediaDataController.getInstance(currentAccount).getEntities(result, supportsSendingNewEntities()); if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; photoEntry.caption = result[0]; photoEntry.entities = entities; } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage photoEntry = (MediaController.SearchImage) object; photoEntry.caption = result[0]; photoEntry.entities = entities; } if (captionEditText.getFieldCharSequence().length() != 0 && !placeProvider.isPhotoChecked(currentIndex)) { setPhotoChecked(); } setCurrentCaption(null, result[0], false); } captionEditText.setTag(null); if (lastTitle != null) { actionBar.setTitle(lastTitle); lastTitle = null; } if (isCurrentVideo) { actionBar.setSubtitle(muteVideo ? LocaleController.getString("SoundMuted", R.string.SoundMuted) : currentSubtitle); } updateCaptionTextForCurrentPhoto(object); if (captionEditText.isPopupShowing()) { captionEditText.hidePopup(); } captionEditText.closeKeyboard(); if (Build.VERSION.SDK_INT >= 19) { captionEditText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); } } private void updateVideoPlayerTime() { String newText; if (videoPlayer == null) { newText = String.format("%02d:%02d / %02d:%02d", 0, 0, 0, 0); } else { long current = videoPlayer.getCurrentPosition(); if (current < 0) { current = 0; } long total = videoPlayer.getDuration(); if (total < 0) { total = 0; } if (total != C.TIME_UNSET && current != C.TIME_UNSET) { if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { total *= (videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()); current -= videoTimelineView.getLeftProgress() * total; if (current > total) { current = total; } } current /= 1000; total /= 1000; newText = String.format("%02d:%02d / %02d:%02d", current / 60, current % 60, total / 60, total % 60); } else { newText = String.format("%02d:%02d / %02d:%02d", 0, 0, 0, 0); } } videoPlayerTime.setText(newText); } private void checkBufferedProgress(float progress) { if (!isStreaming || parentActivity == null || streamingAlertShown || videoPlayer == null || currentMessageObject == null) { return; } TLRPC.Document document = currentMessageObject.getDocument(); if (document == null) { return; } int innerDuration = currentMessageObject.getDuration(); if (innerDuration < 20) { return; } if (progress < 0.9f && (document.size * progress >= 5 * 1024 * 1024 || progress >= 0.5f && document.size >= 2 * 1024 * 1024) && Math.abs(SystemClock.elapsedRealtime() - startedPlayTime) >= 2000) { long duration = videoPlayer.getDuration(); if (duration == C.TIME_UNSET) { Toast toast = Toast.makeText(parentActivity, LocaleController.getString("VideoDoesNotSupportStreaming", R.string.VideoDoesNotSupportStreaming), Toast.LENGTH_LONG); toast.show(); } streamingAlertShown = true; } } public void updateColors() { int color = Theme.getColor(Theme.key_dialogFloatingButton); if (pickerViewSendButton != null) { Drawable drawable = pickerViewSendButton.getBackground(); Theme.setSelectorDrawableColor(drawable, color, false); Theme.setSelectorDrawableColor(drawable, Theme.getColor(Build.VERSION.SDK_INT >= 21 ? Theme.key_dialogFloatingButtonPressed : Theme.key_dialogFloatingButton), true); pickerViewSendButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingIcon), PorterDuff.Mode.SRC_IN)); } if (checkImageView != null) { checkImageView.setColor(Theme.getColor(Theme.key_dialogFloatingButton), 0xffffffff); } PorterDuffColorFilter filter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN); if (timeItem != null && timeItem.getColorFilter() != null) { timeItem.setColorFilter(filter); } if (paintItem != null && paintItem.getColorFilter() != null) { paintItem.setColorFilter(filter); } if (cropItem != null && cropItem.getColorFilter() != null) { cropItem.setColorFilter(filter); } if (tuneItem != null && tuneItem.getColorFilter() != null) { tuneItem.setColorFilter(filter); } if (editorDoneLayout != null) { editorDoneLayout.doneButton.setTextColor(color); } if (qualityPicker != null) { qualityPicker.doneButton.setTextColor(color); } if (photoPaintView != null) { photoPaintView.updateColors(); } if (photoFilterView != null) { photoFilterView.updateColors(); } if (captionEditText != null) { captionEditText.updateColors(); } if (selectedPhotosListView != null) { int count = selectedPhotosListView.getChildCount(); for (int a = 0; a < count; a++) { View view = selectedPhotosListView.getChildAt(a); if (view instanceof PhotoPickerPhotoCell) { ((PhotoPickerPhotoCell) view).updateColors(); } } } if (masksAlert != null) { masksAlert.updateColors(true); } } public void injectVideoPlayer(VideoPlayer player) { injectingVideoPlayer = player; } public void injectVideoPlayerSurface(SurfaceTexture surface) { injectingVideoPlayerSurface = surface; } public boolean isInjectingVideoPlayer() { return injectingVideoPlayer != null; } private void scheduleActionBarHide() { scheduleActionBarHide(3000); } private void scheduleActionBarHide(int delay) { if (!isAccessibilityEnabled()) { AndroidUtilities.cancelRunOnUIThread(hideActionBarRunnable); AndroidUtilities.runOnUIThread(hideActionBarRunnable, delay); } } private boolean isAccessibilityEnabled() { try { AccessibilityManager am = (AccessibilityManager) actvityContext.getSystemService(Context.ACCESSIBILITY_SERVICE); return am.isEnabled(); } catch (Exception e) { FileLog.e(e); } return false; } private void updatePlayerState(boolean playWhenReady, int playbackState) { if (videoPlayer == null) { return; } if (isStreaming) { if (playbackState == ExoPlayer.STATE_BUFFERING && skipFirstBufferingProgress) { if (playWhenReady) { skipFirstBufferingProgress = false; } } else { final boolean buffering = seekToProgressPending != 0 || playbackState == ExoPlayer.STATE_BUFFERING; if (buffering) { AndroidUtilities.cancelRunOnUIThread(hideActionBarRunnable); } else { scheduleActionBarHide(); } toggleMiniProgress(buffering, true); } } if (playWhenReady && (playbackState != ExoPlayer.STATE_ENDED && playbackState != ExoPlayer.STATE_IDLE)) { try { parentActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); keepScreenOnFlagSet = true; } catch (Exception e) { FileLog.e(e); } } else { try { parentActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); keepScreenOnFlagSet = false; } catch (Exception e) { FileLog.e(e); } } if (playbackState == ExoPlayer.STATE_READY || playbackState == ExoPlayer.STATE_IDLE) { if (currentMessageObject != null) { videoPreviewFrame.open(videoPlayer.getCurrentUri()); } if (seekToProgressPending != 0) { int seekTo = (int) (videoPlayer.getDuration() * seekToProgressPending); videoPlayer.seekTo(seekTo); seekToProgressPending = 0; if (currentMessageObject != null && !FileLoader.getInstance(currentMessageObject.currentAccount).isLoadingVideoAny(currentMessageObject.getDocument())) { skipFirstBufferingProgress = true; } } } if (playbackState == ExoPlayer.STATE_READY) { if (aspectRatioFrameLayout.getVisibility() != View.VISIBLE) { aspectRatioFrameLayout.setVisibility(View.VISIBLE); } if (!pipItem.isEnabled()) { pipAvailable = true; pipItem.setEnabled(true); pipItem.animate().alpha(1.0f).setDuration(175).withEndAction(null).start(); } playerWasReady = true; if (currentMessageObject != null && currentMessageObject.isVideo()) { AndroidUtilities.cancelRunOnUIThread(setLoadingRunnable); FileLoader.getInstance(currentMessageObject.currentAccount).removeLoadingVideo(currentMessageObject.getDocument(), true, false); } } else if (playbackState == ExoPlayer.STATE_BUFFERING) { if (playWhenReady && currentMessageObject != null && currentMessageObject.isVideo()) { if (playerWasReady) { setLoadingRunnable.run(); } else { AndroidUtilities.runOnUIThread(setLoadingRunnable, 1000); } } } if (videoPlayer.isPlaying() && playbackState != ExoPlayer.STATE_ENDED) { if (!isPlaying) { isPlaying = true; photoProgressViews[0].setBackgroundState(isCurrentVideo ? PROGRESS_NONE : PROGRESS_PAUSE, false); photoProgressViews[0].setIndexedAlpha(1, !isCurrentVideo && !isAccessibilityEnabled() && ((playerAutoStarted && !playerWasPlaying) || !isActionBarVisible) ? 0f : 1f, false); playerWasPlaying = true; AndroidUtilities.runOnUIThread(updateProgressRunnable); } } else if (isPlaying) { isPlaying = false; if (currentEditMode != 3) { photoProgressViews[0].setIndexedAlpha(1, 1f, false); photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false); } AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); if (playbackState == ExoPlayer.STATE_ENDED) { if (isCurrentVideo) { if (!videoTimelineView.isDragging()) { videoTimelineView.setProgress(0.0f); if (!inPreview && (currentEditMode != 0 || videoTimelineView.getVisibility() == View.VISIBLE)) { videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); } else { videoPlayer.seekTo(0); } if (currentEditMode == 0) { videoPlayer.pause(); } else { videoPlayer.play(); } containerView.invalidate(); } } else { videoPlayerSeekbar.setProgress(0.0f); videoPlayerSeekbarView.invalidate(); if (!inPreview && videoTimelineView.getVisibility() == View.VISIBLE) { videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); } else { videoPlayer.seekTo(0); } videoPlayer.pause(); if (!isActionBarVisible) { toggleActionBar(true, true); } } if (pipVideoView != null) { pipVideoView.onVideoCompleted(); } } } if (pipVideoView != null) { pipVideoView.updatePlayButton(); } updateVideoPlayerTime(); } private void preparePlayer(Uri uri, boolean playWhenReady, boolean preview) { preparePlayer(uri, playWhenReady, preview, null); } private void preparePlayer(Uri uri, boolean playWhenReady, boolean preview, MediaController.SavedFilterState savedFilterState) { if (!preview) { currentPlayingVideoFile = uri; currentSavedFilterState = savedFilterState; } if (parentActivity == null) { return; } streamingAlertShown = false; startedPlayTime = SystemClock.elapsedRealtime(); currentVideoFinishedLoading = false; lastBufferedPositionCheck = 0; firstAnimationDelay = true; inPreview = preview; releasePlayer(false); if (imagesArrLocals.isEmpty()) { createVideoTextureView(null); } if (Build.VERSION.SDK_INT >= 21 && textureImageView == null) { textureImageView = new ImageView(parentActivity); textureImageView.setBackgroundColor(0xffff0000); textureImageView.setPivotX(0); textureImageView.setPivotY(0); textureImageView.setVisibility(View.INVISIBLE); containerView.addView(textureImageView); } textureUploaded = false; videoCrossfadeStarted = false; boolean newPlayerCreated = false; playerWasReady = false; playerWasPlaying = false; if (videoPlayer == null) { if (injectingVideoPlayer != null) { videoPlayer = injectingVideoPlayer; injectingVideoPlayer = null; playerInjected = true; updatePlayerState(videoPlayer.getPlayWhenReady(), videoPlayer.getPlaybackState()); } else { videoPlayer = new VideoPlayer() { @Override public void play() { super.play(); playOrStopAnimatedStickers(true); } @Override public void pause() { super.pause(); if (currentEditMode == 0) { playOrStopAnimatedStickers(false); } } }; newPlayerCreated = true; } if (videoTextureView != null) { videoPlayer.setTextureView(videoTextureView); } videoPlayer.setDelegate(new VideoPlayer.VideoPlayerDelegate() { @Override public void onStateChanged(boolean playWhenReady, int playbackState) { updatePlayerState(playWhenReady, playbackState); } @Override public void onError(VideoPlayer player, Exception e) { if (videoPlayer != player) { return; } FileLog.e(e); if (!menuItem.isSubItemVisible(gallery_menu_openin)) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("CantPlayVideo", R.string.CantPlayVideo)); builder.setPositiveButton(LocaleController.getString("Open", R.string.Open), (dialog, which) -> { try { AndroidUtilities.openForView(currentMessageObject, parentActivity); closePhoto(false, false); } catch (Exception e1) { FileLog.e(e1); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showAlertDialog(builder); } @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); if (videoTextureView instanceof VideoEditTextureView) { ((VideoEditTextureView) videoTextureView).setVideoSize((int) (width * pixelWidthHeightRatio), height); } } } @Override public void onRenderedFirstFrame() { if (!textureUploaded) { textureUploaded = true; containerView.invalidate(); } } @Override public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { if (changingTextureView) { changingTextureView = false; if (isInline) { if (isInline) { waitingForFirstTextureUpload = 1; } changedTextureView.setSurfaceTexture(surfaceTexture); changedTextureView.setSurfaceTextureListener(surfaceTextureListener); changedTextureView.setVisibility(View.VISIBLE); return true; } } return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { if (waitingForFirstTextureUpload == 2) { if (textureImageView != null) { textureImageView.setVisibility(View.INVISIBLE); textureImageView.setImageDrawable(null); if (currentBitmap != null) { currentBitmap.recycle(); currentBitmap = null; } } switchingInlineMode = false; if (Build.VERSION.SDK_INT >= 21) { aspectRatioFrameLayout.getLocationInWindow(pipPosition); //pipPosition[0] -= getLeftInset(); pipPosition[1] -= containerView.getTranslationY(); textureImageView.setTranslationX(textureImageView.getTranslationX() + getLeftInset()); videoTextureView.setTranslationX(videoTextureView.getTranslationX() + getLeftInset() - aspectRatioFrameLayout.getX()); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( ObjectAnimator.ofFloat(textureImageView, View.SCALE_X, 1.0f), ObjectAnimator.ofFloat(textureImageView, View.SCALE_Y, 1.0f), ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_X, pipPosition[0]), ObjectAnimator.ofFloat(textureImageView, View.TRANSLATION_Y, pipPosition[1]), ObjectAnimator.ofFloat(videoTextureView, View.SCALE_X, 1.0f), ObjectAnimator.ofFloat(videoTextureView, View.SCALE_Y, 1.0f), ObjectAnimator.ofFloat(videoTextureView, View.TRANSLATION_X, pipPosition[0] - aspectRatioFrameLayout.getX()), ObjectAnimator.ofFloat(videoTextureView, View.TRANSLATION_Y, pipPosition[1] - aspectRatioFrameLayout.getY()), ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 255), ObjectAnimator.ofFloat(actionBar, View.ALPHA, 1.0f), ObjectAnimator.ofFloat(bottomLayout, View.ALPHA, 1.0f), ObjectAnimator.ofFloat(captionTextViewSwitcher, View.ALPHA, 1.0f), ObjectAnimator.ofFloat(groupedPhotosListView, View.ALPHA, 1.0f) ); animatorSet.setInterpolator(new DecelerateInterpolator()); animatorSet.setDuration(250); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { pipAnimationInProgress = false; } }); animatorSet.start(); } else { //containerView.setTranslationY(0); } waitingForFirstTextureUpload = 0; } } }); } if (!imagesArrLocals.isEmpty()) { createVideoTextureView(savedFilterState); } videoTextureView.setAlpha(videoCrossfadeAlpha = 0.0f); if (paintingOverlay != null) { paintingOverlay.setAlpha(videoCrossfadeAlpha); } shouldSavePositionForCurrentVideo = null; shouldSavePositionForCurrentVideoShortTerm = null; lastSaveTime = 0; if (newPlayerCreated) { seekToProgressPending = seekToProgressPending2; videoPlayerSeekbar.setProgress(0); videoTimelineView.setProgress(0); videoPlayerSeekbar.setBufferedProgress(0); if (currentMessageObject != null) { final int duration = currentMessageObject.getDuration(); final String name = currentMessageObject.getFileName(); if (!TextUtils.isEmpty(name)) { if (duration >= 20 * 60) { if (currentMessageObject.forceSeekTo < 0) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("media_saved_pos", Activity.MODE_PRIVATE); float pos = preferences.getFloat(name, -1); if (pos > 0 && pos < 0.999f) { currentMessageObject.forceSeekTo = pos; videoPlayerSeekbar.setProgress(pos); } } shouldSavePositionForCurrentVideo = name; } else if (duration >= 10) { SavedVideoPosition videoPosition = null; for (int i = savedVideoPositions.size() - 1; i >= 0; i--) { final SavedVideoPosition item = savedVideoPositions.valueAt(i); if (item.timestamp < SystemClock.elapsedRealtime() - 5 * 1000) { savedVideoPositions.removeAt(i); } else if (videoPosition == null && savedVideoPositions.keyAt(i).equals(name)) { videoPosition = item; } } if (currentMessageObject.forceSeekTo < 0 && videoPosition != null) { float pos = videoPosition.position; if (pos > 0 && pos < 0.999f) { currentMessageObject.forceSeekTo = pos; videoPlayerSeekbar.setProgress(pos); } } shouldSavePositionForCurrentVideoShortTerm = name; } } } videoPlayer.preparePlayer(uri, "other"); videoPlayer.setPlayWhenReady(playWhenReady); } playerLooping = currentMessageObject != null && currentMessageObject.getDuration() <= 30; videoPlayerControlFrameLayout.setSeekBarTransitionEnabled(playerLooping); videoPlayer.setLooping(playerLooping); if (currentMessageObject != null && currentMessageObject.forceSeekTo >= 0) { seekToProgressPending = currentMessageObject.forceSeekTo; currentMessageObject.forceSeekTo = -1; } if (currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document))) { bottomLayout.setVisibility(View.VISIBLE); bottomLayout.setPadding(0, 0, AndroidUtilities.dp(84), 0); pickerView.setVisibility(View.GONE); } else { bottomLayout.setPadding(0, 0, 0, 0); } setVideoPlayerControlVisible(!isCurrentVideo, true); if (!isCurrentVideo) { scheduleActionBarHide(playerAutoStarted ? 3000 : 1000); } inPreview = preview; } private void createVideoTextureView(MediaController.SavedFilterState savedFilterState) { if (videoTextureView != null) { return; } aspectRatioFrameLayout = new AspectRatioFrameLayout(parentActivity) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (textureImageView != null) { ViewGroup.LayoutParams layoutParams = textureImageView.getLayoutParams(); layoutParams.width = getMeasuredWidth(); layoutParams.height = getMeasuredHeight(); } } }; aspectRatioFrameLayout.setVisibility(View.INVISIBLE); containerView.addView(aspectRatioFrameLayout, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER)); if (imagesArrLocals.isEmpty()) { videoTextureView = new TextureView(parentActivity); } else { VideoEditTextureView videoEditTextureView = new VideoEditTextureView(parentActivity, videoPlayer); if (savedFilterState != null) { videoEditTextureView.setDelegate(thread -> thread.setFilterGLThreadDelegate(FilterShaders.getFilterShadersDelegate(savedFilterState))); } videoTextureView = videoEditTextureView; } if (injectingVideoPlayerSurface != null) { videoTextureView.setSurfaceTexture(injectingVideoPlayerSurface); textureUploaded = true; injectingVideoPlayerSurface = null; } videoTextureView.setPivotX(0); videoTextureView.setPivotY(0); videoTextureView.setOpaque(false); aspectRatioFrameLayout.addView(videoTextureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER)); } private void releasePlayer(boolean onClose) { if (videoPlayer != null) { AndroidUtilities.cancelRunOnUIThread(setLoadingRunnable); AndroidUtilities.cancelRunOnUIThread(hideActionBarRunnable); if (shouldSavePositionForCurrentVideoShortTerm != null) { final float progress = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration(); savedVideoPositions.put(shouldSavePositionForCurrentVideoShortTerm, new SavedVideoPosition(progress, SystemClock.elapsedRealtime())); } videoPlayer.releasePlayer(true); videoPlayer = null; } else { playerWasPlaying = false; } videoPreviewFrame.close(); toggleMiniProgress(false, false); pipAvailable = false; playerInjected = false; if (pipItem.isEnabled()) { pipItem.setEnabled(false); pipItem.animate().alpha(0.5f).setDuration(175).withEndAction(null).start(); } if (keepScreenOnFlagSet) { try { parentActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); keepScreenOnFlagSet = false; } catch (Exception e) { FileLog.e(e); } } if (aspectRatioFrameLayout != null) { try { containerView.removeView(aspectRatioFrameLayout); } catch (Throwable ignore) { } aspectRatioFrameLayout = null; } if (videoTextureView != null) { if (videoTextureView instanceof VideoEditTextureView) { ((VideoEditTextureView) videoTextureView).release(); } videoTextureView = null; } if (isPlaying) { isPlaying = false; AndroidUtilities.cancelRunOnUIThread(updateProgressRunnable); } if (!onClose && !inPreview && !requestingPreview) { setVideoPlayerControlVisible(false, true); } photoProgressViews[0].resetAlphas(); } private void setVideoPlayerControlVisible(boolean visible, boolean animated) { if (videoPlayerControlVisible != visible) { if (videoPlayerControlAnimator != null) { videoPlayerControlAnimator.cancel(); } videoPlayerControlVisible = visible; if (animated) { if (visible) { videoPlayerControlFrameLayout.setVisibility(View.VISIBLE); } else { dateTextView.setVisibility(View.VISIBLE); nameTextView.setVisibility(View.VISIBLE); if (allowShare) { shareButton.setVisibility(View.VISIBLE); } } final boolean shareWasAllowed = allowShare; final ValueAnimator anim = ValueAnimator.ofFloat(videoPlayerControlFrameLayout.getAlpha(), visible ? 1f : 0f); anim.setDuration(200); anim.addUpdateListener(a -> { final float alpha = (float) a.getAnimatedValue(); videoPlayerControlFrameLayout.setAlpha(alpha); dateTextView.setAlpha(1f - alpha); nameTextView.setAlpha(1f - alpha); if (shareWasAllowed) { shareButton.setAlpha(1f - alpha); } }); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (!visible) { videoPlayerControlFrameLayout.setVisibility(View.GONE); } else { dateTextView.setVisibility(View.GONE); nameTextView.setVisibility(View.GONE); if (shareWasAllowed) { shareButton.setVisibility(View.GONE); } } } }); videoPlayerControlAnimator = anim; anim.start(); } else { videoPlayerControlFrameLayout.setVisibility(visible ? View.VISIBLE : View.GONE); videoPlayerControlFrameLayout.setAlpha(visible ? 1f : 0f); dateTextView.setVisibility(visible ? View.GONE : View.VISIBLE); dateTextView.setAlpha(visible ? 0f : 1f); nameTextView.setVisibility(visible ? View.GONE : View.VISIBLE); nameTextView.setAlpha(visible ? 0f : 1f); if (allowShare) { shareButton.setVisibility(visible ? View.GONE : View.VISIBLE); shareButton.setAlpha(visible ? 0f : 1f); } } if (allowShare) { if (visible) { menuItem.showSubItem(gallery_menu_share); } else { 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 (TextUtils.isEmpty(caption)) { captionEditText.setFieldText(""); } else { captionEditText.setFieldText(caption); } captionEditText.setAllowTextEntitiesIntersection(supportsSendingNewEntities()); } public void showAlertDialog(AlertDialog.Builder builder) { if (parentActivity == null) { return; } try { if (visibleDialog != null) { visibleDialog.dismiss(); visibleDialog = null; } } catch (Exception e) { FileLog.e(e); } try { visibleDialog = builder.show(); visibleDialog.setCanceledOnTouchOutside(true); visibleDialog.setOnDismissListener(dialog -> visibleDialog = null); } catch (Exception e) { FileLog.e(e); } } private static final int thumbSize = 512; private void mergeThumbs(String finalPath, String thumbPath, Bitmap thumb, Bitmap bitmap, boolean reverse) { try { boolean recycle = false; if (thumb == null) { thumb = BitmapFactory.decodeFile(thumbPath); recycle = true; } int w = thumb.getWidth(); int h = thumb.getHeight(); float size = thumbSize; if (w > size || h > size) { float scale = Math.max(w, h) / size; w /= scale; h /= scale; } Bitmap dst = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(dst); Rect dstRect = new Rect(0, 0, w, h); if (reverse) { canvas.drawBitmap(bitmap, null, dstRect, bitmapPaint); canvas.drawBitmap(thumb, null, dstRect, bitmapPaint); } else { canvas.drawBitmap(thumb, null, dstRect, bitmapPaint); canvas.drawBitmap(bitmap, null, dstRect, bitmapPaint); } FileOutputStream stream = new FileOutputStream(new File(finalPath)); dst.compress(Bitmap.CompressFormat.JPEG, 83, stream); try { stream.close(); } catch (Exception e) { FileLog.e(e); } if (recycle) { thumb.recycle(); } dst.recycle(); } catch (Throwable e) { FileLog.e(e); } } private void playOrStopAnimatedStickers(boolean play) { if (currentMediaEntities != null) { for (int a = 0, N = currentMediaEntities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = currentMediaEntities.get(a); if (entity.type == 0 && (entity.subType & 1) != 0 && entity.view instanceof BackupImageView) { ImageReceiver imageReceiver = ((BackupImageView) entity.view).getImageReceiver(); RLottieDrawable drawable = imageReceiver.getLottieAnimation(); if (drawable == null) { continue; } if (play) { drawable.start(); } else { drawable.stop(); } } } } } private boolean hasAnimatedMediaEntities() { if (currentMediaEntities != null) { for (int a = 0, N = currentMediaEntities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = currentMediaEntities.get(a); if (entity.type == 0 && (entity.subType & 1) != 0) { return true; } } } return false; } private void applyCurrentEditMode() { Bitmap bitmap = null; Bitmap[] paintThumbBitmap = new Bitmap[1]; ArrayList stickers = null; MediaController.SavedFilterState savedFilterState = null; ArrayList entities = null; MediaController.MediaEditState entry = (MediaController.MediaEditState) imagesArrLocals.get(currentIndex); if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { bitmap = photoCropView.getBitmap(entry); } else if (currentEditMode == 2) { bitmap = photoFilterView.getBitmap(); savedFilterState = photoFilterView.getSavedFilterState(); } else if (currentEditMode == 3) { if (Build.VERSION.SDK_INT >= 18 && (sendPhotoType == 0 || sendPhotoType == 2)) { entities = new ArrayList<>(); } bitmap = photoPaintView.getBitmap(entities, paintThumbBitmap); stickers = photoPaintView.getMasks(); } if (bitmap != null) { TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(bitmap, currentEditMode == 3 ? Bitmap.CompressFormat.PNG : Bitmap.CompressFormat.JPEG, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), 87, false, 101, 101); if (size != null) { if (entry.thumbPath != null) { new File(entry.thumbPath).delete(); entry.thumbPath = null; } if (currentEditMode == 1 || currentEditMode == 0 && sendPhotoType == SELECT_TYPE_AVATAR) { if (entry.filterPath == null) { if (entry.croppedPath != null) { new File(entry.croppedPath).delete(); } entry.croppedPath = currentImagePath = FileLoader.getPathToAttach(size, true).toString(); } else { if (entry.filterPath != null) { new File(entry.filterPath).delete(); } entry.filterPath = currentImagePath = FileLoader.getPathToAttach(size, true).toString(); } if (entry.imagePath != null) { new File(entry.imagePath).delete(); } if (entry.paintPath != null) { File f = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_temp.jpg"); mergeThumbs(entry.thumbPath = f.getAbsolutePath(), entry.fullPaintPath, null, bitmap, true); Bitmap paintBitmap = BitmapFactory.decodeFile(entry.paintPath); paintingOverlay.setBitmap(paintBitmap); if (entry.fullPaintPath != null && !entry.paintPath.equals(entry.fullPaintPath)) { paintBitmap = BitmapFactory.decodeFile(hasAnimatedMediaEntities() ? entry.paintPath : entry.fullPaintPath); } Bitmap canvasBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas b = new Canvas(canvasBitmap); b.drawBitmap(bitmap, null, new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()), bitmapPaint); b.drawBitmap(paintBitmap, null, new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()), bitmapPaint); size = ImageLoader.scaleAndSaveImage(canvasBitmap, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), 87, false, 101, 101); entry.imagePath = FileLoader.getPathToAttach(size, true).toString(); canvasBitmap.recycle(); paintingOverlay.setEntities(currentMediaEntities, isCurrentVideo, true); } else { size = ImageLoader.scaleAndSaveImage(bitmap, thumbSize, thumbSize, 70, false, 101, 101); entry.thumbPath = FileLoader.getPathToAttach(size, true).toString(); try { File f = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_temp.jpg"); AndroidUtilities.copyFile(new File(entry.croppedPath), f); entry.imagePath = f.getAbsolutePath(); } catch (Exception e) { FileLog.e(e); } } } else if (currentEditMode == 2) { if (entry.filterPath != null) { new File(entry.filterPath).delete(); } entry.filterPath = currentImagePath = FileLoader.getPathToAttach(size, true).toString(); if (entry.paintPath != null && !hasAnimatedMediaEntities() && !isCurrentVideo) { Bitmap paintBitmap; boolean recycle; if (entry.paintPath.equals(entry.fullPaintPath)) { paintBitmap = paintingOverlay.getBitmap(); recycle = false; } else { paintBitmap = BitmapFactory.decodeFile(entry.fullPaintPath); recycle = true; } Bitmap canvasBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas b = new Canvas(canvasBitmap); b.drawBitmap(bitmap, null, new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()), bitmapPaint); b.drawBitmap(paintBitmap, null, new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()), bitmapPaint); size = ImageLoader.scaleAndSaveImage(canvasBitmap, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), 87, false, 101, 101); if (entry.imagePath != null) { new File(entry.imagePath).delete(); } entry.imagePath = FileLoader.getPathToAttach(size, true).toString(); size = ImageLoader.scaleAndSaveImage(canvasBitmap, thumbSize, thumbSize, 70, false, 101, 101); entry.thumbPath = FileLoader.getPathToAttach(size, true).toString(); if (recycle) { paintBitmap.recycle(); } canvasBitmap.recycle(); } else if (entry.paintPath == null) { try { File f = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_temp.jpg"); AndroidUtilities.copyFile(new File(entry.filterPath), f); entry.thumbPath = f.getAbsolutePath(); } catch (Exception e) { FileLog.e(e); } if (!hasAnimatedMediaEntities()) { if (entry.imagePath != null) { new File(entry.imagePath).delete(); } try { File f = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_temp.jpg"); AndroidUtilities.copyFile(new File(entry.filterPath), f); entry.imagePath = f.getAbsolutePath(); } catch (Exception e) { FileLog.e(e); } } } else { File f = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_temp.jpg"); mergeThumbs(entry.thumbPath = f.getAbsolutePath(), entry.fullPaintPath, entry.paintPath.equals(entry.fullPaintPath) ? paintingOverlay.getThumb() : null, paintThumbBitmap[0] != null ? paintThumbBitmap[0] : bitmap, true); } } else if (currentEditMode == 3) { if (entry.paintPath != null) { new File(entry.paintPath).delete(); if (!entry.paintPath.equals(entry.fullPaintPath)) { new File(entry.fullPaintPath).delete(); } } entry.stickers = stickers; entry.paintPath = currentPaintPath = FileLoader.getPathToAttach(size, true).toString(); paintingOverlay.setEntities(entry.mediaEntities = currentMediaEntities = entities == null || entities.isEmpty() ? null : entities, isCurrentVideo, true); entry.averageDuration = currentAverageDuration = photoPaintView.getLcm(); if (entry.mediaEntities != null && paintThumbBitmap[0] != null) { size = ImageLoader.scaleAndSaveImage(paintThumbBitmap[0], Bitmap.CompressFormat.PNG, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), 87, false, 101, 101); entry.fullPaintPath = FileLoader.getPathToAttach(size, true).toString(); } else { entry.fullPaintPath = entry.paintPath; } paintingOverlay.setBitmap(bitmap); if (!hasAnimatedMediaEntities() && !isCurrentVideo) { String path; if (entry.filterPath != null) { path = entry.filterPath; } else if (entry.croppedPath != null) { path = entry.croppedPath; } else { path = entry.getPath(); } Bitmap originalBitmap = ImageLoader.loadBitmap(path, null, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), true); if (originalBitmap != null && !originalBitmap.isMutable()) { originalBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true); } if (originalBitmap != null) { Canvas b = new Canvas(originalBitmap); b.drawBitmap(paintThumbBitmap[0] != null ? paintThumbBitmap[0] : bitmap, null, new Rect(0, 0, originalBitmap.getWidth(), originalBitmap.getHeight()), bitmapPaint); size = ImageLoader.scaleAndSaveImage(originalBitmap, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), 87, false, 101, 101); if (entry.imagePath != null) { new File(entry.imagePath).delete(); } entry.imagePath = FileLoader.getPathToAttach(size, true).toString(); size = ImageLoader.scaleAndSaveImage(originalBitmap, thumbSize, thumbSize, 70, false, 101, 101); entry.thumbPath = FileLoader.getPathToAttach(size, true).toString(); } } else if (entry.filterPath == null) { if (entry.imagePath != null) { new File(entry.imagePath).delete(); entry.imagePath = null; } Bitmap originalBitmap; if (isCurrentVideo) { VideoEditTextureView textureView = (VideoEditTextureView) videoTextureView; originalBitmap = SendMessagesHelper.createVideoThumbnailAtTime(entry.getPath(), (long) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration() * 1000L)); } else { String path; if (entry.croppedPath != null) { path = entry.croppedPath; } else { path = entry.getPath(); } originalBitmap = ImageLoader.loadBitmap(path, null, thumbSize, thumbSize, true); if (originalBitmap != null && !originalBitmap.isMutable()) { originalBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true); } } if (originalBitmap != null) { Canvas b = new Canvas(originalBitmap); b.drawBitmap(paintThumbBitmap[0] != null ? paintThumbBitmap[0] : bitmap, null, new Rect(0, 0, originalBitmap.getWidth(), originalBitmap.getHeight()), bitmapPaint); size = ImageLoader.scaleAndSaveImage(originalBitmap, thumbSize, thumbSize, 70, false, 101, 101); entry.thumbPath = FileLoader.getPathToAttach(size, true).toString(); } } else { File f = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_temp.jpg"); mergeThumbs(entry.thumbPath = f.getAbsolutePath(), entry.filterPath, null, paintThumbBitmap[0] != null ? paintThumbBitmap[0] : bitmap, false); } } SharedConfig.saveConfig(); if (savedFilterState != null) { entry.savedFilterState = currentSavedFilterState = savedFilterState; } if (currentEditMode == 1) { entry.isCropped = true; cropItem.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN)); } else if (currentEditMode == 2) { entry.isFiltered = true; tuneItem.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN)); } else if (currentEditMode == 3) { entry.isPainted = true; paintItem.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN)); } if ((sendPhotoType == 0 || sendPhotoType == 4) && placeProvider != null) { placeProvider.updatePhotoAtIndex(currentIndex); if (!placeProvider.isPhotoChecked(currentIndex)) { setPhotoChecked(); } } if (currentEditMode == 1) { float scaleX = photoCropView.getRectSizeX() / (float) getContainerViewWidth(); float scaleY = photoCropView.getRectSizeY() / (float) getContainerViewHeight(); scale = Math.max(scaleX, scaleY); translationX = photoCropView.getRectX() + photoCropView.getRectSizeX() / 2 - getContainerViewWidth() / 2; translationY = photoCropView.getRectY() + photoCropView.getRectSizeY() / 2 - getContainerViewHeight() / 2; zoomAnimation = true; applying = true; photoCropView.onDisappear(); } centerImage.setParentView(null); ignoreDidSetImage = true; if (!isCurrentVideo && currentEditMode != 3) { centerImage.setImageBitmap(bitmap); centerImage.setOrientation(0, true); containerView.requestLayout(); } ignoreDidSetImage = false; centerImage.setParentView(containerView); if (sendPhotoType == SELECT_TYPE_AVATAR) { setCropBitmap(); } } } } private void setPhotoChecked() { if (placeProvider != null) { if (placeProvider.getSelectedPhotos() != null && maxSelectedPhotos > 0 && placeProvider.getSelectedPhotos().size() >= maxSelectedPhotos && !placeProvider.isPhotoChecked(currentIndex)) { if (allowOrder && parentChatActivity != null) { TLRPC.Chat chat = parentChatActivity.getCurrentChat(); if (chat != null && !ChatObject.hasAdminRights(chat) && chat.slowmode_enabled) { AlertsCreator.createSimpleAlert(parentActivity, LocaleController.getString("Slowmode", R.string.Slowmode), LocaleController.getString("SlowmodeSelectSendError", R.string.SlowmodeSelectSendError)).show(); } } return; } int num = placeProvider.setPhotoChecked(currentIndex, getCurrentVideoEditedInfo()); boolean checked = placeProvider.isPhotoChecked(currentIndex); checkImageView.setChecked(checked, true); if (num >= 0) { if (checked) { selectedPhotosAdapter.notifyItemInserted(num); selectedPhotosListView.smoothScrollToPosition(num); } else { selectedPhotosAdapter.notifyItemRemoved(num); if (num == 0) { selectedPhotosAdapter.notifyItemChanged(0); } } } updateSelectedCount(); } } private void createCropView() { if (photoCropView != null) { return; } photoCropView = new PhotoCropView(actvityContext); photoCropView.setVisibility(View.GONE); int index = containerView.indexOfChild(pickerViewSendButton); containerView.addView(photoCropView, index - 1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 48)); photoCropView.setDelegate(reset -> resetButton.setVisibility(reset ? View.GONE : View.VISIBLE)); } private void switchToEditMode(final int mode) { if (currentEditMode == mode || (isCurrentVideo && photoProgressViews[0].backgroundState != 3) && !isCurrentVideo && (centerImage.getBitmap() == null || photoProgressViews[0].backgroundState != -1) || changeModeAnimation != null || imageMoveAnimation != null || captionEditText.getTag() != null) { return; } if (mode == 0) { // no edit mode 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 = Math.min(scaleX, scaleY); float newScale = Math.min(newScaleX, newScaleY); if (sendPhotoType == SELECT_TYPE_AVATAR) { setCropTranslations(true); } else { animateToScale = newScale / scale; animateToX = 0; translationX = getLeftInset() / 2 - getRightInset() / 2; if (currentEditMode == 1) { animateToY = AndroidUtilities.dp(24 + 34); } else if (currentEditMode == 2) { animateToY = AndroidUtilities.dp(92); } else if (currentEditMode == 3) { animateToY = AndroidUtilities.dp(44); } if (Build.VERSION.SDK_INT >= 21) { animateToY -= AndroidUtilities.statusBarHeight / 2; } animationStartTime = System.currentTimeMillis(); zoomAnimation = true; } } padImageForHorizontalInsets = false; imageMoveAnimation = new AnimatorSet(); ArrayList animators = new ArrayList<>(4); if (currentEditMode == 1) { animators.add(ObjectAnimator.ofFloat(editorDoneLayout, View.TRANSLATION_Y, AndroidUtilities.dp(48))); animators.add(ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1)); animators.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0)); } else if (currentEditMode == 2) { photoFilterView.shutdown(); animators.add(ObjectAnimator.ofFloat(photoFilterView.getToolsView(), View.TRANSLATION_Y, AndroidUtilities.dp(186))); animators.add(ObjectAnimator.ofFloat(photoFilterView.getCurveControl(), View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(photoFilterView.getBlurControl(), View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1)); } else if (currentEditMode == 3) { paintingOverlay.showAll(); containerView.invalidate(); photoPaintView.shutdown(); animators.add(ObjectAnimator.ofFloat(photoPaintView.getToolsView(), View.TRANSLATION_Y, AndroidUtilities.dp(126))); animators.add(ObjectAnimator.ofFloat(photoPaintView.getColorPicker(), View.TRANSLATION_Y, AndroidUtilities.dp(126))); animators.add(ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1)); } imageMoveAnimation.playTogether(animators); imageMoveAnimation.setDuration(200); imageMoveAnimation.addListener(new AnimatorListenerAdapter() { @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; applying = false; if (sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.setVisibility(View.VISIBLE); } else { animateToScale = 1; animateToX = 0; animateToY = 0; scale = 1; } updateMinMax(scale); containerView.invalidate(); AnimatorSet animatorSet = new AnimatorSet(); ArrayList arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, 0)); arrayList.add(ObjectAnimator.ofFloat(pickerViewSendButton, View.TRANSLATION_Y, 0)); if (sendPhotoType != SELECT_TYPE_AVATAR) { arrayList.add(ObjectAnimator.ofFloat(actionBar, View.TRANSLATION_Y, 0)); } if (needCaptionLayout) { arrayList.add(ObjectAnimator.ofFloat(captionTextViewSwitcher, View.TRANSLATION_Y, 0)); } if (sendPhotoType == 0 || sendPhotoType == 4) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, View.ALPHA, 1)); arrayList.add(ObjectAnimator.ofFloat(photosCounterView, View.ALPHA, 1)); } else if (sendPhotoType == SELECT_TYPE_AVATAR) { arrayList.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 1)); } if (cameraItem.getTag() != null) { cameraItem.setVisibility(View.VISIBLE); arrayList.add(ObjectAnimator.ofFloat(cameraItem, View.ALPHA, 1)); } if (muteItem.getTag() != null) { muteItem.setVisibility(View.VISIBLE); arrayList.add(ObjectAnimator.ofFloat(muteItem, View.ALPHA, 1)); } animatorSet.playTogether(arrayList); animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { pickerView.setVisibility(View.VISIBLE); pickerViewSendButton.setVisibility(View.VISIBLE); actionBar.setVisibility(View.VISIBLE); if (needCaptionLayout) { captionTextViewSwitcher.setVisibility(captionTextViewSwitcher.getTag() != null ? View.VISIBLE : View.INVISIBLE); } if (sendPhotoType == 0 || sendPhotoType == 4 || (sendPhotoType == 2 || sendPhotoType == 5) && imagesArrLocals.size() > 1) { checkImageView.setVisibility(View.VISIBLE); photosCounterView.setVisibility(View.VISIBLE); } else if (sendPhotoType == SELECT_TYPE_AVATAR) { setCropTranslations(false); } } }); animatorSet.start(); } }); imageMoveAnimation.start(); } else if (mode == 1) { // crop createCropView(); photoCropView.onAppear(); editorDoneLayout.doneButton.setText(LocaleController.getString("Crop", R.string.Crop)); editorDoneLayout.doneButton.setTextColor(Theme.getColor(Theme.key_dialogFloatingButton)); changeModeAnimation = new AnimatorSet(); ArrayList arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); arrayList.add(ObjectAnimator.ofFloat(pickerViewSendButton, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); arrayList.add(ObjectAnimator.ofFloat(actionBar, View.TRANSLATION_Y, 0, -actionBar.getHeight())); if (needCaptionLayout) { arrayList.add(ObjectAnimator.ofFloat(captionTextViewSwitcher, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); } if (sendPhotoType == 0 || sendPhotoType == 4) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, View.ALPHA, 1, 0)); arrayList.add(ObjectAnimator.ofFloat(photosCounterView, View.ALPHA, 1, 0)); } if (selectedPhotosListView.getVisibility() == View.VISIBLE) { arrayList.add(ObjectAnimator.ofFloat(selectedPhotosListView, View.ALPHA, 1, 0)); } if (cameraItem.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(cameraItem, View.ALPHA, 1, 0)); } if (muteItem.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(muteItem, View.ALPHA, 1, 0)); } changeModeAnimation.playTogether(arrayList); changeModeAnimation.setDuration(200); changeModeAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { changeModeAnimation = null; pickerView.setVisibility(View.GONE); pickerViewSendButton.setVisibility(View.GONE); cameraItem.setVisibility(View.GONE); muteItem.setVisibility(View.GONE); selectedPhotosListView.setVisibility(View.GONE); selectedPhotosListView.setAlpha(0.0f); selectedPhotosListView.setTranslationY(-AndroidUtilities.dp(10)); photosCounterView.setRotationX(0.0f); selectedPhotosListView.setEnabled(false); isPhotosListViewVisible = false; if (needCaptionLayout) { captionTextViewSwitcher.setVisibility(View.INVISIBLE); } if (sendPhotoType == 0 || sendPhotoType == 4 || (sendPhotoType == 2 || sendPhotoType == 5) && imagesArrLocals.size() > 1) { checkImageView.setVisibility(View.GONE); photosCounterView.setVisibility(View.GONE); } final Bitmap bitmap = centerImage.getBitmap(); if (bitmap != null) { photoCropView.setBitmap(bitmap, centerImage.getOrientation(), sendPhotoType != SELECT_TYPE_AVATAR, false, paintingOverlay); photoCropView.onDisappear(); 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 = Math.min(scaleX, scaleY); float newScale = Math.min(newScaleX, newScaleY); if (sendPhotoType == SELECT_TYPE_AVATAR) { float minSide = Math.min(getContainerViewWidth(1), getContainerViewHeight(1)); newScaleX = minSide / (float) bitmapWidth; newScaleY = minSide / (float) bitmapHeight; newScale = Math.max(newScaleX, newScaleY); } animateToScale = newScale / scale; animateToX = getLeftInset() / 2 - getRightInset() / 2; animateToY = -AndroidUtilities.dp(24 + 32) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight / 2 : 0); animationStartTime = System.currentTimeMillis(); zoomAnimation = true; } imageMoveAnimation = new AnimatorSet(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(editorDoneLayout, View.TRANSLATION_Y, AndroidUtilities.dp(48), 0), ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1), ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0, 1) ); imageMoveAnimation.setDuration(200); imageMoveAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { editorDoneLayout.setVisibility(View.VISIBLE); photoCropView.setVisibility(View.VISIBLE); } @Override public void onAnimationEnd(Animator animation) { photoCropView.onAppeared(); imageMoveAnimation = null; currentEditMode = mode; animateToScale = 1; animateToX = 0; animateToY = 0; scale = 1; updateMinMax(scale); padImageForHorizontalInsets = true; containerView.invalidate(); } }); imageMoveAnimation.start(); } }); changeModeAnimation.start(); } else if (mode == 2) { // filter if (isCurrentVideo && videoPlayer != null && !videoPlayer.isPlaying()) { if (!muteVideo) { videoPlayer.setVolume(0); } toggleVideoPlayer(); } if (photoFilterView == null) { MediaController.SavedFilterState state = null; Bitmap bitmap; String originalPath = null; int orientation = 0; if (!imagesArrLocals.isEmpty()) { Object object = imagesArrLocals.get(currentIndex); if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry entry = (MediaController.PhotoEntry) object; orientation = entry.orientation; } MediaController.MediaEditState editState = (MediaController.MediaEditState) object; state = editState.savedFilterState; if (editState.croppedPath != null) { originalPath = editState.croppedPath; orientation = 0; } else { originalPath = editState.getPath(); } } if (videoTextureView != null) { bitmap = null; } else { if (state == null) { bitmap = centerImage.getBitmap(); orientation = centerImage.getOrientation(); } else { bitmap = BitmapFactory.decodeFile(originalPath); } } photoFilterView = new PhotoFilterView(parentActivity, videoTextureView != null ? (VideoEditTextureView) videoTextureView : null, bitmap, orientation, state, isCurrentVideo ? null : paintingOverlay); containerView.addView(photoFilterView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); photoFilterView.getDoneTextView().setOnClickListener(v -> { applyCurrentEditMode(); switchToEditMode(0); }); photoFilterView.getCancelTextView().setOnClickListener(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("NekoX", R.string.NekoX)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> switchToEditMode(0)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showAlertDialog(builder); } else { switchToEditMode(0); } }); photoFilterView.getToolsView().setTranslationY(AndroidUtilities.dp(186)); } changeModeAnimation = new AnimatorSet(); ArrayList arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); arrayList.add(ObjectAnimator.ofFloat(pickerViewSendButton, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); arrayList.add(ObjectAnimator.ofFloat(actionBar, View.TRANSLATION_Y, 0, -actionBar.getHeight())); if (sendPhotoType == 0 || sendPhotoType == 4) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, View.ALPHA, 1, 0)); arrayList.add(ObjectAnimator.ofFloat(photosCounterView, View.ALPHA, 1, 0)); } else if (sendPhotoType == SELECT_TYPE_AVATAR) { arrayList.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 1, 0)); } if (selectedPhotosListView.getVisibility() == View.VISIBLE) { arrayList.add(ObjectAnimator.ofFloat(selectedPhotosListView, View.ALPHA, 1, 0)); } if (cameraItem.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(cameraItem, View.ALPHA, 1, 0)); } if (muteItem.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(muteItem, View.ALPHA, 1, 0)); } changeModeAnimation.playTogether(arrayList); changeModeAnimation.setDuration(200); changeModeAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { changeModeAnimation = null; pickerView.setVisibility(View.GONE); pickerViewSendButton.setVisibility(View.GONE); actionBar.setVisibility(View.GONE); cameraItem.setVisibility(View.GONE); muteItem.setVisibility(View.GONE); if (photoCropView != null) { photoCropView.setVisibility(View.INVISIBLE); } selectedPhotosListView.setVisibility(View.GONE); selectedPhotosListView.setAlpha(0.0f); selectedPhotosListView.setTranslationY(-AndroidUtilities.dp(10)); photosCounterView.setRotationX(0.0f); selectedPhotosListView.setEnabled(false); isPhotosListViewVisible = false; if (needCaptionLayout) { captionTextViewSwitcher.setVisibility(View.INVISIBLE); } if (sendPhotoType == 0 || sendPhotoType == 4 || (sendPhotoType == 2 || sendPhotoType == 5) && imagesArrLocals.size() > 1) { checkImageView.setVisibility(View.GONE); photosCounterView.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 = Math.min(scaleX, scaleY); float newScale = Math.min(newScaleX, newScaleY); animateToScale = newScale / scale; animateToX = getLeftInset() / 2 - getRightInset() / 2; animateToY = -AndroidUtilities.dp(92) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight / 2 : 0); animationStartTime = System.currentTimeMillis(); zoomAnimation = true; } imageMoveAnimation = new AnimatorSet(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1), ObjectAnimator.ofFloat(photoFilterView.getToolsView(), View.TRANSLATION_Y, AndroidUtilities.dp(186), 0) ); imageMoveAnimation.setDuration(200); imageMoveAnimation.addListener(new AnimatorListenerAdapter() { @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); padImageForHorizontalInsets = true; containerView.invalidate(); if (sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.reset(); } } }); imageMoveAnimation.start(); } }); changeModeAnimation.start(); } else if (mode == 3) { if (isCurrentVideo && videoPlayer != null && !videoPlayer.isPlaying()) { if (!muteVideo) { videoPlayer.setVolume(0); } toggleVideoPlayer(); } if (photoPaintView == null) { int w; int h; if (videoTextureView != null) { VideoEditTextureView textureView = (VideoEditTextureView) videoTextureView; w = textureView.getVideoWidth(); h = textureView.getVideoHeight(); while (w > 1280 || h > 1280) { w /= 2; h /= 2; } } else { w = centerImage.getBitmapWidth(); h = centerImage.getBitmapHeight(); } Bitmap bitmap = paintingOverlay.getBitmap(); if (bitmap == null) { bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); } photoPaintView = new PhotoPaintView(parentActivity, bitmap, isCurrentVideo ? null : centerImage.getBitmap(), centerImage.getOrientation(), currentMediaEntities, () -> paintingOverlay.hideBitmap()) { @Override protected void onOpenCloseStickersAlert(boolean open) { if (videoPlayer != null) { if (open) { videoPlayer.pause(); } else { videoPlayer.play(); } } } }; containerView.addView(photoPaintView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); photoPaintView.getDoneTextView().setOnClickListener(v -> { applyCurrentEditMode(); switchToEditMode(0); }); photoPaintView.getCancelTextView().setOnClickListener(v -> photoPaintView.maybeShowDismissalAlert(PhotoViewer.this, parentActivity, () -> switchToEditMode(0))); photoPaintView.getColorPicker().setTranslationY(AndroidUtilities.dp(126)); photoPaintView.getToolsView().setTranslationY(AndroidUtilities.dp(126)); } changeModeAnimation = new AnimatorSet(); ArrayList arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); arrayList.add(ObjectAnimator.ofFloat(pickerViewSendButton, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); arrayList.add(ObjectAnimator.ofFloat(actionBar, View.TRANSLATION_Y, 0, -actionBar.getHeight())); if (needCaptionLayout) { arrayList.add(ObjectAnimator.ofFloat(captionTextViewSwitcher, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); } if (sendPhotoType == 0 || sendPhotoType == 4) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, View.ALPHA, 1, 0)); arrayList.add(ObjectAnimator.ofFloat(photosCounterView, View.ALPHA, 1, 0)); } else if (sendPhotoType == SELECT_TYPE_AVATAR) { arrayList.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 1, 0)); } if (selectedPhotosListView.getVisibility() == View.VISIBLE) { arrayList.add(ObjectAnimator.ofFloat(selectedPhotosListView, View.ALPHA, 1, 0)); } if (cameraItem.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(cameraItem, View.ALPHA, 1, 0)); } if (muteItem.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(muteItem, View.ALPHA, 1, 0)); } changeModeAnimation.playTogether(arrayList); changeModeAnimation.setDuration(200); changeModeAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { changeModeAnimation = null; pickerView.setVisibility(View.GONE); pickerViewSendButton.setVisibility(View.GONE); cameraItem.setVisibility(View.GONE); muteItem.setVisibility(View.GONE); if (photoCropView != null) { photoCropView.setVisibility(View.INVISIBLE); } selectedPhotosListView.setVisibility(View.GONE); selectedPhotosListView.setAlpha(0.0f); selectedPhotosListView.setTranslationY(-AndroidUtilities.dp(10)); photosCounterView.setRotationX(0.0f); selectedPhotosListView.setEnabled(false); isPhotosListViewVisible = false; if (needCaptionLayout) { captionTextViewSwitcher.setVisibility(View.INVISIBLE); } if (sendPhotoType == 0 || sendPhotoType == 4 || (sendPhotoType == 2 || sendPhotoType == 5) && imagesArrLocals.size() > 1) { checkImageView.setVisibility(View.GONE); photosCounterView.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 = Math.min(scaleX, scaleY); float newScale = Math.min(newScaleX, newScaleY); animateToScale = newScale / scale; animateToX = getLeftInset() / 2 - getRightInset() / 2; animateToY = -AndroidUtilities.dp(44) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight / 2 : 0); animationStartTime = System.currentTimeMillis(); zoomAnimation = true; } imageMoveAnimation = new AnimatorSet(); imageMoveAnimation.playTogether( ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1), ObjectAnimator.ofFloat(photoPaintView.getColorPicker(), View.TRANSLATION_Y, AndroidUtilities.dp(126), 0), ObjectAnimator.ofFloat(photoPaintView.getToolsView(), View.TRANSLATION_Y, AndroidUtilities.dp(126), 0) ); imageMoveAnimation.setDuration(200); imageMoveAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { photoPaintView.init(); paintingOverlay.hideEntities(); imageMoveAnimation = null; currentEditMode = mode; animateToScale = 1; animateToX = 0; animateToY = 0; scale = 1; updateMinMax(scale); padImageForHorizontalInsets = true; containerView.invalidate(); if (sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.reset(); } } }); imageMoveAnimation.start(); } }); changeModeAnimation.start(); } } private void toggleCheckImageView(boolean show) { AnimatorSet animatorSet = new AnimatorSet(); ArrayList arrayList = new ArrayList<>(); final float offsetY = AndroidUtilities.dpf2(24); arrayList.add(ObjectAnimator.ofFloat(pickerView, View.ALPHA, show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, show ? 0.0f : offsetY)); arrayList.add(ObjectAnimator.ofFloat(pickerViewSendButton, View.ALPHA, show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(pickerViewSendButton, View.TRANSLATION_Y, show ? 0.0f : offsetY)); if (sendPhotoType == 0 || sendPhotoType == 4) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, View.ALPHA, show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(checkImageView, View.TRANSLATION_Y, show ? 0.0f : -offsetY)); arrayList.add(ObjectAnimator.ofFloat(photosCounterView, View.ALPHA, show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(photosCounterView, View.TRANSLATION_Y, show ? 0.0f : -offsetY)); } animatorSet.playTogether(arrayList); animatorSet.setDuration(200); animatorSet.start(); } private void toggleMiniProgressInternal(final boolean show) { if (show) { miniProgressView.setVisibility(View.VISIBLE); } miniProgressAnimator = new AnimatorSet(); miniProgressAnimator.playTogether(ObjectAnimator.ofFloat(miniProgressView, View.ALPHA, show ? 1.0f : 0.0f)); miniProgressAnimator.setDuration(200); miniProgressAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (animation.equals(miniProgressAnimator)) { if (!show) { miniProgressView.setVisibility(View.INVISIBLE); } miniProgressAnimator = null; } } @Override public void onAnimationCancel(Animator animation) { if (animation.equals(miniProgressAnimator)) { miniProgressAnimator = null; } } }); miniProgressAnimator.start(); } private void toggleMiniProgress(final boolean show, final boolean animated) { AndroidUtilities.cancelRunOnUIThread(miniProgressShowRunnable); if (animated) { toggleMiniProgressInternal(show); if (show) { if (miniProgressAnimator != null) { miniProgressAnimator.cancel(); miniProgressAnimator = null; } if (firstAnimationDelay) { firstAnimationDelay = false; toggleMiniProgressInternal(true); } else { AndroidUtilities.runOnUIThread(miniProgressShowRunnable, 500); } } else { if (miniProgressAnimator != null) { miniProgressAnimator.cancel(); toggleMiniProgressInternal(false); } } } else { if (miniProgressAnimator != null) { miniProgressAnimator.cancel(); miniProgressAnimator = null; } miniProgressView.setAlpha(show ? 1.0f : 0.0f); miniProgressView.setVisibility(show ? View.VISIBLE : View.INVISIBLE); } } private void updateContainerFlags(boolean actionBarVisible) { if (Build.VERSION.SDK_INT >= 21 && sendPhotoType != SELECT_TYPE_AVATAR && containerView != null) { int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; if (!actionBarVisible) { flags |= View.SYSTEM_UI_FLAG_FULLSCREEN; if (containerView.getPaddingLeft() > 0 || containerView.getPaddingRight() > 0) { flags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; } } containerView.setSystemUiVisibility(flags); } } private void toggleActionBar(final boolean show, final boolean animated) { if (actionBarAnimator != null) { actionBarAnimator.cancel(); } if (show) { actionBar.setVisibility(View.VISIBLE); if (bottomLayout.getTag() != null) { bottomLayout.setVisibility(View.VISIBLE); } if (captionTextViewSwitcher.getTag() != null) { captionTextViewSwitcher.setVisibility(View.VISIBLE); if (videoPreviewFrame != null) { videoPreviewFrame.requestLayout(); } } } isActionBarVisible = show; updateContainerFlags(show); if (videoPlayerControlVisible && isPlaying && show) { scheduleActionBarHide(); } else { AndroidUtilities.cancelRunOnUIThread(hideActionBarRunnable); } final float offsetY = AndroidUtilities.dpf2(24); if (animated) { ArrayList arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(actionBar, View.ALPHA, show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(actionBar, View.TRANSLATION_Y, show ? 0 : -offsetY)); if (bottomLayout != null) { arrayList.add(ObjectAnimator.ofFloat(bottomLayout, View.ALPHA, show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(bottomLayout, View.TRANSLATION_Y, show ? 0 : offsetY)); } if (videoPlayerControlVisible) { arrayList.add(ObjectAnimator.ofFloat(videoPlayerControlFrameLayout, VPC_PROGRESS, show ? 1.0f : 0.0f)); } else { videoPlayerControlFrameLayout.setProgress(show ? 1.0f : 0.0f); } arrayList.add(ObjectAnimator.ofFloat(groupedPhotosListView, View.ALPHA, show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(groupedPhotosListView, View.TRANSLATION_Y, show ? 0 : offsetY)); if (!needCaptionLayout && captionScrollView != null) { arrayList.add(ObjectAnimator.ofFloat(captionScrollView, View.ALPHA, show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(captionScrollView, View.TRANSLATION_Y, show ? 0 : offsetY)); } if (videoPlayerControlVisible && isPlaying) { final ValueAnimator anim = ValueAnimator.ofFloat(photoProgressViews[0].animAlphas[1], show ? 1.0f : 0.0f); anim.addUpdateListener(a -> photoProgressViews[0].setIndexedAlpha(1, (float) a.getAnimatedValue(), false)); arrayList.add(anim); } if (muteItem.getTag() != null) { arrayList.add(ObjectAnimator.ofFloat(muteItem, View.ALPHA, show ? 1.0f : 0.0f)); } actionBarAnimator = new AnimatorSet(); actionBarAnimator.playTogether(arrayList); actionBarAnimator.setDuration(200); actionBarAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (animation.equals(actionBarAnimator)) { if (!show) { actionBar.setVisibility(View.INVISIBLE); if (bottomLayout.getTag() != null) { bottomLayout.setVisibility(View.INVISIBLE); } if (captionTextViewSwitcher.getTag() != null) { captionTextViewSwitcher.setVisibility(View.INVISIBLE); } } actionBarAnimator = null; } } @Override public void onAnimationCancel(Animator animation) { if (animation.equals(actionBarAnimator)) { actionBarAnimator = null; } } }); actionBarAnimator.start(); } else { actionBar.setAlpha(show ? 1.0f : 0.0f); actionBar.setTranslationY(show ? 0 : -offsetY); bottomLayout.setAlpha(show ? 1.0f : 0.0f); bottomLayout.setTranslationY(show ? 0 : offsetY); groupedPhotosListView.setAlpha(show ? 1.0f : 0.0f); groupedPhotosListView.setTranslationY(show ? 0 : offsetY); if (!needCaptionLayout && captionScrollView != null) { captionScrollView.setAlpha(show ? 1.0f : 0.0f); captionScrollView.setTranslationY(show ? 0 : offsetY); } videoPlayerControlFrameLayout.setProgress(show ? 1.0f : 0.0f); if (muteItem.getTag() != null) { muteItem.setAlpha(show ? 1.0f : 0.0f); } if (videoPlayerControlVisible && isPlaying) { photoProgressViews[0].setIndexedAlpha(1, show ? 1f : 0f, false); } } } private void togglePhotosListView(boolean show, final boolean animated) { if (show == isPhotosListViewVisible) { return; } if (show) { selectedPhotosListView.setVisibility(View.VISIBLE); } isPhotosListViewVisible = show; selectedPhotosListView.setEnabled(show); if (animated) { ArrayList arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(selectedPhotosListView, View.ALPHA, show ? 1.0f : 0.0f)); arrayList.add(ObjectAnimator.ofFloat(selectedPhotosListView, View.TRANSLATION_Y, show ? 0 : -AndroidUtilities.dp(10))); arrayList.add(ObjectAnimator.ofFloat(photosCounterView, View.ROTATION_X, show ? 1.0f : 0.0f)); currentListViewAnimation = new AnimatorSet(); currentListViewAnimation.playTogether(arrayList); if (!show) { currentListViewAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (currentListViewAnimation != null && currentListViewAnimation.equals(animation)) { selectedPhotosListView.setVisibility(View.GONE); currentListViewAnimation = null; } } }); } currentListViewAnimation.setDuration(200); currentListViewAnimation.start(); } else { selectedPhotosListView.setAlpha(show ? 1.0f : 0.0f); selectedPhotosListView.setTranslationY(show ? 0 : -AndroidUtilities.dp(10)); photosCounterView.setRotationX(show ? 1.0f : 0.0f); if (!show) { selectedPhotosListView.setVisibility(View.GONE); } } } private void toggleVideoPlayer() { if (videoPlayer == null) { return; } AndroidUtilities.cancelRunOnUIThread(hideActionBarRunnable); if (isPlaying) { videoPlayer.pause(); } else { if (isCurrentVideo) { if (Math.abs(videoTimelineView.getProgress() - 1.0f) < 0.01f || videoPlayer.getCurrentPosition() == videoPlayer.getDuration()) { videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); } } else { if (Math.abs(videoPlayerSeekbar.getProgress() - 1.0f) < 0.01f || videoPlayer.getCurrentPosition() == videoPlayer.getDuration()) { videoPlayer.seekTo(0); } scheduleActionBarHide(); } videoPlayer.play(); } containerView.invalidate(); } private String getFileName(int index) { if (index < 0) { return null; } if (!secureDocuments.isEmpty()) { if (index >= secureDocuments.size()) { return null; } SecureDocument location = secureDocuments.get(index); return location.secureFile.dc_id + "_" + location.secureFile.id + ".jpg"; } else if (!imagesArrLocations.isEmpty() || !imagesArr.isEmpty()) { if (!imagesArrLocations.isEmpty()) { if (index >= imagesArrLocations.size()) { return null; } ImageLocation location = imagesArrLocations.get(index); if (location == null) { return null; } return location.location.volume_id + "_" + location.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); return searchImage.getAttachName(); } 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 instanceof TLRPC.TL_webDocument) { return Utilities.MD5(botInlineResult.content.url) + "." + ImageLoader.getHttpUrlExtension(botInlineResult.content.url, FileLoader.getMimeTypePart(botInlineResult.content.mime_type)); } } } return null; } private ImageLocation getImageLocation(int index, int[] size) { if (index < 0) { return null; } if (!secureDocuments.isEmpty()) { if (index >= secureDocuments.size()) { return null; } if (size != null) { size[0] = secureDocuments.get(index).secureFile.size; } return ImageLocation.getForSecureDocument(secureDocuments.get(index)); } else if (!imagesArrLocations.isEmpty()) { if (index >= imagesArrLocations.size()) { return null; } if (size != 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 null; } else { TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); if (sizeFull != null) { if (size != null) { size[0] = sizeFull.size; if (size[0] == 0) { size[0] = -1; } } return ImageLocation.getForObject(sizeFull, message.photoThumbsObject); } else if (size != null) { 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) { if (message.isGif()) { return ImageLocation.getForDocument(message.getDocument()); } else { TLRPC.FileLocation location; TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); if (sizeFull != null) { if (size != null) { size[0] = sizeFull.size; if (size[0] == 0) { size[0] = -1; } } return ImageLocation.getForObject(sizeFull, message.photoThumbsObject); } else if (size != null) { size[0] = -1; } } } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice) { return ImageLocation.getForWebFile(WebFile.createWithWebDocument(((TLRPC.TL_messageMediaInvoice) message.messageOwner.media).photo)); } else if (message.getDocument() != null) { TLRPC.Document document = message.getDocument(); if (sharedMediaType == MediaDataController.MEDIA_GIF) { return ImageLocation.getForDocument(document); } else if (MessageObject.isDocumentHasThumb(message.getDocument())) { TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); if (size != null) { size[0] = thumb.size; if (size[0] == 0) { size[0] = -1; } } return ImageLocation.getForDocument(thumb, document); } } } return null; } private TLObject getFileLocation(int index, int[] size) { if (index < 0) { return null; } if (!secureDocuments.isEmpty()) { if (index >= secureDocuments.size()) { return null; } if (size != null) { size[0] = secureDocuments.get(index).secureFile.size; } return secureDocuments.get(index); } else if (!imagesArrLocations.isEmpty()) { if (index >= imagesArrLocations.size()) { return null; } if (size != null) { size[0] = imagesArrLocationsSizes.get(index); } return imagesArrLocations.get(index).location; } 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) { if (size != null) { size[0] = sizeFull.size; if (size[0] == 0) { size[0] = -1; } } return sizeFull; } else if (size != null) { 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.FileLocation location; TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); if (sizeFull != null) { if (size != null) { size[0] = sizeFull.size; if (size[0] == 0) { size[0] = -1; } } return sizeFull; } else if (size != null) { size[0] = -1; } } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice) { return ((TLRPC.TL_messageMediaInvoice) message.messageOwner.media).photo; } else if (message.getDocument() != null && MessageObject.isDocumentHasThumb(message.getDocument())) { TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(message.getDocument().thumbs, 90); if (size != null) { size[0] = thumb.size; if (size[0] == 0) { size[0] = -1; } } return thumb; } } return null; } private void updateSelectedCount() { if (placeProvider == null) { return; } int count = placeProvider.getSelectedCount(); photosCounterView.setCount(count); if (count == 0) { togglePhotosListView(false, true); } } private void setItemVisible(View itemView, boolean visible, boolean animate) { setItemVisible(itemView, visible, animate, 1.0f); } private void setItemVisible(View itemView, boolean visible, boolean animate, float maxAlpha) { Boolean visibleNow = actionBarItemsVisibility.get(itemView); if (visibleNow == null || visibleNow != visible) { actionBarItemsVisibility.put(itemView, visible); itemView.animate().cancel(); final float alpha = (visible ? 1f : 0f) * maxAlpha; if (animate && visibleNow != null) { if (visible) { itemView.setVisibility(View.VISIBLE); } itemView.animate().alpha(alpha).setDuration(100).setInterpolator(new LinearInterpolator()).withEndAction(() -> { if (!visible) { itemView.setVisibility(View.GONE); } }).start(); } else { itemView.setVisibility(visible ? View.VISIBLE : View.GONE); itemView.setAlpha(alpha); } } } private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, ImageLocation imageLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, int index, final PlaceProviderObject object) { classGuid = ConnectionsManager.generateClassGuid(); currentMessageObject = null; currentFileLocation = null; currentSecureDocument = null; currentPathObject = null; fromCamera = false; 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; containerView.setTag(1); playerAutoStarted = false; isCurrentVideo = false; imagesArr.clear(); imagesArrLocations.clear(); imagesArrLocationsSizes.clear(); avatarsArr.clear(); secureDocuments.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); if (currentThumb != null) { currentThumb.release(); } currentThumb = object != null ? object.thumb : null; isEvent = object != null && object.isEvent; sharedMediaType = MediaDataController.MEDIA_PHOTOVIDEO; allMediaItem.setText(LocaleController.getString("ShowAllMedia", R.string.ShowAllMedia)); menuItem.setVisibility(View.VISIBLE); setItemVisible(sendNoQuoteItem, false, false); setItemVisible(sendItem, false, false); setItemVisible(pipItem, false, true); cameraItem.setVisibility(View.GONE); cameraItem.setTag(null); bottomLayout.setVisibility(View.VISIBLE); bottomLayout.setTag(1); bottomLayout.setTranslationY(0); captionTextViewSwitcher.setTranslationY(0); shareButton.setVisibility(View.GONE); if (qualityChooseView != null) { qualityChooseView.setVisibility(View.INVISIBLE); qualityPicker.setVisibility(View.INVISIBLE); qualityChooseView.setTag(null); } if (qualityChooseViewAnimation != null) { qualityChooseViewAnimation.cancel(); qualityChooseViewAnimation = null; } setDoubleTapEnabled(true); allowShare = false; slideshowMessageId = 0; nameOverride = null; dateOverride = 0; menuItem.hideSubItem(gallery_menu_showall); menuItem.hideSubItem(gallery_menu_showinchat); menuItem.hideSubItem(gallery_menu_share); menuItem.hideSubItem(gallery_menu_openin); menuItem.hideSubItem(gallery_menu_savegif); menuItem.hideSubItem(gallery_menu_masks2); actionBar.setTranslationY(0); checkImageView.setAlpha(1.0f); checkImageView.setTranslationY(0.0f); checkImageView.setVisibility(View.GONE); actionBar.setTitleRightMargin(0); photosCounterView.setAlpha(1.0f); photosCounterView.setTranslationY(0.0f); photosCounterView.setVisibility(View.GONE); pickerView.setVisibility(View.GONE); pickerViewSendButton.setVisibility(View.GONE); pickerViewSendButton.setTranslationY(0); pickerView.setAlpha(1.0f); pickerViewSendButton.setAlpha(1.0f); pickerView.setTranslationY(0); paintItem.setVisibility(View.GONE); paintItem.setTag(null); cropItem.setVisibility(View.GONE); tuneItem.setVisibility(View.GONE); tuneItem.setTag(null); timeItem.setVisibility(View.GONE); rotateItem.setVisibility(View.GONE); pickerView.getLayoutParams().height = LayoutHelper.WRAP_CONTENT; docInfoTextView.setVisibility(View.GONE); docNameTextView.setVisibility(View.GONE); videoTimelineView.setVisibility(View.GONE); compressItem.setVisibility(View.GONE); captionEditText.setVisibility(View.GONE); mentionListView.setVisibility(View.GONE); muteItem.setVisibility(View.GONE); muteItem.setTag(null); actionBar.setSubtitle(null); setItemVisible(masksItem, false, true); muteVideo = false; muteItem.setImageResource(R.drawable.video_send_unmute); editorDoneLayout.setVisibility(View.GONE); captionTextViewSwitcher.setTag(null); captionTextViewSwitcher.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 (photoProgressViews[a] != null) { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, false); } } if (messageObject != null && messages == null) { if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageObject.messageOwner.media.webpage != null) { TLRPC.WebPage webPage = messageObject.messageOwner.media.webpage; String siteName = webPage.site_name; if (siteName != null) { siteName = siteName.toLowerCase(); if (siteName.equals("instagram") || siteName.equals("twitter") || "telegram_album".equals(webPage.type)) { if (!TextUtils.isEmpty(webPage.author)) { nameOverride = webPage.author; } if (webPage.cached_page instanceof TLRPC.TL_page) { for (int a = 0; a < webPage.cached_page.blocks.size(); a++) { TLRPC.PageBlock block = webPage.cached_page.blocks.get(a); if (block instanceof TLRPC.TL_pageBlockAuthorDate) { dateOverride = ((TLRPC.TL_pageBlockAuthorDate) block).published_date; break; } } } ArrayList arrayList = messageObject.getWebPagePhotos(null, null); if (!arrayList.isEmpty()) { slideshowMessageId = messageObject.getId(); needSearchImageInArr = false; imagesArr.addAll(arrayList); totalImagesCount = imagesArr.size(); int idx = imagesArr.indexOf(messageObject); if (idx < 0) { idx = 0; } setImageIndex(idx); } } } } if (messageObject.canPreviewDocument()) { sharedMediaType = MediaDataController.MEDIA_FILE; allMediaItem.setText(LocaleController.getString("ShowAllFiles", R.string.ShowAllFiles)); } else if (messageObject.isGif()) { sharedMediaType = MediaDataController.MEDIA_GIF; allMediaItem.setText(LocaleController.getString("ShowAllGIFs", R.string.ShowAllGIFs)); } if (slideshowMessageId == 0) { imagesArr.add(messageObject); if (messageObject.eventId != 0) { needSearchImageInArr = false; } else if (currentAnimation != null) { needSearchImageInArr = false; if (messageObject.canForwardMessage()) { setItemVisible(sendNoQuoteItem, true, false); setItemVisible(sendItem, true, false); } } else if (!messageObject.scheduled && !(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice) && !(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_showinchat); menuItem.showSubItem(gallery_menu_showall); setItemVisible(sendNoQuoteItem, true, false); setItemVisible(sendItem, true, false); } setImageIndex(0); } } else if (documents != null) { secureDocuments.addAll(documents); setImageIndex(index); } else if (fileLocation != null) { avatarsDialogId = object.dialogId; if (imageLocation == null) { if (avatarsDialogId > 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(avatarsDialogId); imageLocation = ImageLocation.getForUser(user, true); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-avatarsDialogId); imageLocation = ImageLocation.getForChat(chat, true); } } if (imageLocation == null) { return; } imagesArrLocations.add(imageLocation); currentUserAvatarLocation = imageLocation; imagesArrLocationsSizes.add(object.size); avatarsArr.add(new TLRPC.TL_photoEmpty()); shareButton.setVisibility(!videoPlayerControlVisible ? 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); } else if (messages != null) { imagesArr.addAll(messages); for (int a = 0; a < imagesArr.size(); a++) { MessageObject message = imagesArr.get(a); imagesByIds[message.getDialogId() == currentDialogId ? 0 : 1].put(message.getId(), message); } MessageObject openingObject = imagesArr.get(index); if (!openingObject.scheduled) { opennedFromMedia = true; menuItem.showSubItem(gallery_menu_showinchat); if (openingObject.canForwardMessage()) { setItemVisible(sendNoQuoteItem, true, false); setItemVisible(sendItem, true, false); } if (openingObject.canPreviewDocument()) { sharedMediaType = MediaDataController.MEDIA_FILE; allMediaItem.setText(LocaleController.getString("ShowAllFiles", R.string.ShowAllFiles)); } else if (openingObject.isGif()) { sharedMediaType = MediaDataController.MEDIA_GIF; allMediaItem.setText(LocaleController.getString("ShowAllGIFs", R.string.ShowAllGIFs)); } } else { totalImagesCount = imagesArr.size(); } setImageIndex(index); } else if (photos != null) { if (sendPhotoType == 0 || sendPhotoType == 4 || (sendPhotoType == 2 || sendPhotoType == 5) && photos.size() > 1) { checkImageView.setVisibility(View.VISIBLE); photosCounterView.setVisibility(View.VISIBLE); actionBar.setTitleRightMargin(AndroidUtilities.dp(100)); } if ((sendPhotoType == 2 || sendPhotoType == 5) && placeProvider.canCaptureMorePhotos()) { cameraItem.setVisibility(View.VISIBLE); cameraItem.setTag(1); } menuItem.setVisibility(View.GONE); imagesArrLocals.addAll(photos); Object obj = imagesArrLocals.get(index); boolean allowCaption; if (obj instanceof MediaController.PhotoEntry) { if (sendPhotoType == SELECT_TYPE_QR) { cropItem.setVisibility(View.GONE); rotateItem.setVisibility(View.GONE); } else if (isDocumentsPicker) { cropItem.setVisibility(View.GONE); rotateItem.setVisibility(View.GONE); docInfoTextView.setVisibility(View.VISIBLE); docNameTextView.setVisibility(View.VISIBLE); pickerView.getLayoutParams().height = AndroidUtilities.dp(84); } else if (((MediaController.PhotoEntry) obj).isVideo) { cropItem.setVisibility(View.GONE); rotateItem.setVisibility(View.GONE); bottomLayout.setVisibility(View.VISIBLE); bottomLayout.setTag(1); bottomLayout.setTranslationY(-AndroidUtilities.dp(48)); } else { cropItem.setVisibility(sendPhotoType != SELECT_TYPE_AVATAR ? View.VISIBLE : View.GONE); rotateItem.setVisibility(sendPhotoType != SELECT_TYPE_AVATAR ? View.GONE : View.VISIBLE); } allowCaption = !isDocumentsPicker; } else if (obj instanceof TLRPC.BotInlineResult) { cropItem.setVisibility(View.GONE); rotateItem.setVisibility(View.GONE); allowCaption = false; } else { cropItem.setVisibility(obj instanceof MediaController.SearchImage && ((MediaController.SearchImage) obj).type == 0 ? View.VISIBLE : View.GONE); rotateItem.setVisibility(View.GONE); allowCaption = cropItem.getVisibility() == View.VISIBLE; } if (parentChatActivity != null && (parentChatActivity.currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(parentChatActivity.currentEncryptedChat.layer) >= 46)) { mentionsAdapter.setChatInfo(parentChatActivity.chatInfo); mentionsAdapter.setNeedUsernames(parentChatActivity.currentChat != null); mentionsAdapter.setNeedBotContext(false); needCaptionLayout = allowCaption && (placeProvider == null || placeProvider != null && placeProvider.allowCaption()); captionEditText.setVisibility(needCaptionLayout ? View.VISIBLE : View.GONE); if (needCaptionLayout) { captionEditText.onCreate(); } } pickerView.setVisibility(View.VISIBLE); pickerViewSendButton.setVisibility(View.VISIBLE); pickerViewSendButton.setTranslationY(0); pickerViewSendButton.setAlpha(1.0f); bottomLayout.setVisibility(View.GONE); bottomLayout.setTag(null); containerView.setTag(null); setImageIndex(index); if (sendPhotoType == SELECT_TYPE_AVATAR) { paintItem.setVisibility(View.VISIBLE); tuneItem.setVisibility(View.VISIBLE); } else if (sendPhotoType != 4 && sendPhotoType != 5) { paintItem.setVisibility(paintItem.getTag() != null ? View.VISIBLE : View.GONE); tuneItem.setVisibility(tuneItem.getTag() != null ? View.VISIBLE : View.GONE); } else { paintItem.setVisibility(View.GONE); tuneItem.setVisibility(View.GONE); } updateSelectedCount(); } if (currentAnimation == null && !isEvent) { if (currentDialogId != 0 && totalImagesCount == 0 && currentMessageObject != null && !currentMessageObject.scheduled) { MediaDataController.getInstance(currentAccount).getMediaCount(currentDialogId, sharedMediaType, classGuid, true); if (mergeDialogId != 0) { MediaDataController.getInstance(currentAccount).getMediaCount(mergeDialogId, sharedMediaType, classGuid, true); } } else if (avatarsDialogId != 0) { MessagesController.getInstance(currentAccount).loadDialogPhotos(avatarsDialogId, 80, 0, true, classGuid); } } if (currentMessageObject != null && currentMessageObject.isVideo() || currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document))) { playerAutoStarted = true; onActionClick(false); } else if (!imagesArrLocals.isEmpty()) { Object entry = imagesArrLocals.get(index); CharSequence caption = null; TLRPC.User user = parentChatActivity != null ? parentChatActivity.getCurrentUser() : null; boolean allowTimeItem = !isDocumentsPicker && parentChatActivity != null && !parentChatActivity.isSecretChat() && !parentChatActivity.isInScheduleMode() && user != null && !user.bot && !UserObject.isUserSelf(user) && !parentChatActivity.isEditingMessageMedia(); if (entry instanceof TLRPC.BotInlineResult) { allowTimeItem = false; } else if (entry instanceof MediaController.PhotoEntry) { } else if (allowTimeItem && entry instanceof MediaController.SearchImage) { allowTimeItem = ((MediaController.SearchImage) entry).type == 0; } if (allowTimeItem) { timeItem.setVisibility(View.VISIBLE); } } } private void setDoubleTapEnabled(boolean value) { doubleTapEnabled = value; gestureDetector.setOnDoubleTapListener(value ? this : null); } public boolean isMuteVideo() { return muteVideo; } private void setImages() { if (animationInProgress == 0) { setIndexToImage(centerImage, currentIndex); setIndexToImage(rightImage, currentIndex + 1); setIndexToImage(leftImage, currentIndex - 1); } } private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animateCaption) { if (!init && switchingToIndex == index) { return; } menuItem.hideSubItem(gallery_menu_setascurrent); switchingToIndex = index; boolean isVideo = false; boolean sameImage = false; CharSequence caption = null; String newFileName = getFileName(index); MessageObject newMessageObject = null; if (!imagesArr.isEmpty()) { if (switchingToIndex < 0 || switchingToIndex >= imagesArr.size()) { return; } newMessageObject = imagesArr.get(switchingToIndex); isVideo = newMessageObject.isVideo(); boolean isInvoice = newMessageObject.isInvoice(); if (isInvoice) { setItemVisible(masksItem, false, true); menuItem.hideSubItem(gallery_menu_delete); menuItem.hideSubItem(gallery_menu_openin); caption = newMessageObject.messageOwner.media.description; allowShare = false; bottomLayout.setTranslationY(AndroidUtilities.dp(48)); captionTextViewSwitcher.setTranslationY(AndroidUtilities.dp(48)); } else { if (newMessageObject.isNewGif() && ((int) currentDialogId) != 0) { menuItem.showSubItem(gallery_menu_savegif); } if (newMessageObject.canDeleteMessage(parentChatActivity != null && parentChatActivity.isInScheduleMode(), null) && slideshowMessageId == 0) { menuItem.showSubItem(gallery_menu_delete); } else { menuItem.hideSubItem(gallery_menu_delete); } if (isVideo) { menuItem.showSubItem(gallery_menu_openin); final boolean masksItemVisible = masksItem.getVisibility() == View.VISIBLE; if (masksItemVisible) { setItemVisible(masksItem, false, false); } if (!pipAvailable) { pipItem.setEnabled(false); setItemVisible(pipItem, true, !masksItemVisible, 0.5f); } else { setItemVisible(pipItem, true, !masksItemVisible); } if (newMessageObject.hasAttachedStickers() && (int) newMessageObject.getDialogId() != 0) { menuItem.showSubItem(gallery_menu_masks2); } else { menuItem.hideSubItem(gallery_menu_masks2); } } else { menuItem.hideSubItem(gallery_menu_openin); final boolean pipItemVisible = pipItem.getVisibility() == View.VISIBLE; final boolean shouldMasksItemBeVisible = newMessageObject.hasAttachedStickers() && (int) newMessageObject.getDialogId() != 0; if (pipItemVisible) { setItemVisible(pipItem, false, !shouldMasksItemBeVisible); } setItemVisible(masksItem, shouldMasksItemBeVisible, !pipItemVisible); } final boolean shouldAutoPlayed = shouldMessageObjectAutoPlayed(newMessageObject); if (!shouldAutoPlayed) { final boolean animated = !playerWasPlaying; if (nameOverride != null) { nameTextView.setText(nameOverride); } else { if (newMessageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(newMessageObject.messageOwner.from_id); if (user != null) { nameTextView.setText(UserObject.getUserName(user), animated); } else { nameTextView.setText("", animated); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(newMessageObject.messageOwner.to_id.channel_id); if (ChatObject.isChannel(chat) && chat.megagroup && newMessageObject.isForwardedChannelPost()) { chat = MessagesController.getInstance(currentAccount).getChat(newMessageObject.messageOwner.fwd_from.channel_id); } if (chat != null) { nameTextView.setText(chat.title, animated); } else { nameTextView.setText("", animated); } } } long date; if (dateOverride != 0) { date = (long) dateOverride * 1000; } else { date = (long) newMessageObject.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 (newFileName != null && isVideo) { dateTextView.setText(String.format("%s (%s)", dateString, AndroidUtilities.formatFileSize(newMessageObject.getDocument().size)), animated); } else { dateTextView.setText(dateString, animated); } } caption = newMessageObject.caption; } if (currentAnimation != null) { menuItem.hideSubItem(gallery_menu_save); menuItem.hideSubItem(gallery_menu_share); menuItem.hideSubItem(gallery_menu_scan); if (!newMessageObject.canDeleteMessage(parentChatActivity != null && parentChatActivity.isInScheduleMode(), null)) { menuItem.hideSubItem(gallery_menu_delete); } 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 && switchingToIndex > 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; } } MediaDataController.getInstance(currentAccount).loadMedia(loadIndex == 0 ? currentDialogId : mergeDialogId, 40, loadFromMaxId, sharedMediaType, 1, classGuid); loadingMoreImages = true; } actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, switchingToIndex + 1, totalImagesCount + totalImagesCountMerge)); } else { if (imagesArr.size() < totalImagesCount + totalImagesCountMerge && !loadingMoreImages && switchingToIndex < 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; } } MediaDataController.getInstance(currentAccount).loadMedia(loadIndex == 0 ? currentDialogId : mergeDialogId, 80, loadFromMaxId, sharedMediaType, 1, classGuid); loadingMoreImages = true; } actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, (totalImagesCount + totalImagesCountMerge - imagesArr.size()) + switchingToIndex + 1, totalImagesCount + totalImagesCountMerge)); } } else if (slideshowMessageId == 0 && newMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { if (newMessageObject.canPreviewDocument()) { actionBar.setTitle(LocaleController.getString("AttachDocument", R.string.AttachDocument)); } else if (newMessageObject.isVideo()) { actionBar.setTitle(LocaleController.getString("AttachVideo", R.string.AttachVideo)); } else { actionBar.setTitle(LocaleController.getString("AttachPhoto", R.string.AttachPhoto)); } } else if (isInvoice) { actionBar.setTitle(newMessageObject.messageOwner.media.title); } else if (newMessageObject.isVideo()) { actionBar.setTitle(LocaleController.getString("AttachVideo", R.string.AttachVideo)); } else if (newMessageObject.getDocument() != null) { actionBar.setTitle(LocaleController.getString("AttachDocument", R.string.AttachDocument)); } if ((int) currentDialogId == 0) { setItemVisible(sendNoQuoteItem, false, false); setItemVisible(sendItem, false, false); } if (newMessageObject.messageOwner.ttl != 0 && newMessageObject.messageOwner.ttl < 60 * 60) { allowShare = false; menuItem.hideSubItem(gallery_menu_save); shareButton.setVisibility(View.GONE); menuItem.hideSubItem(gallery_menu_scan); menuItem.hideSubItem(gallery_menu_share); } else { allowShare = true; menuItem.showSubItem(gallery_menu_save); menuItem.showSubItem(gallery_menu_scan); shareButton.setVisibility(!videoPlayerControlVisible ? View.VISIBLE : View.GONE); if (shareButton.getVisibility() == View.VISIBLE) { menuItem.hideSubItem(gallery_menu_share); } else { menuItem.showSubItem(gallery_menu_share); } } } groupedPhotosListView.fillList(); } else if (!secureDocuments.isEmpty()) { allowShare = false; menuItem.hideSubItem(gallery_menu_save); menuItem.hideSubItem(gallery_menu_scan); nameTextView.setText(""); dateTextView.setText(""); actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, switchingToIndex + 1, secureDocuments.size())); } else if (!imagesArrLocations.isEmpty()) { if (index < 0 || index >= imagesArrLocations.size()) { return; } if (avatarsDialogId == UserConfig.getInstance(currentAccount).getClientUserId() && index != 0) { menuItem.showSubItem(gallery_menu_setascurrent); } if (avatarsDialogId < 0) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-avatarsDialogId); if (chat != null) { nameTextView.setText(chat.title); } else { nameTextView.setText(""); } } else { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(avatarsDialogId); if (user != null) { nameTextView.setText(UserObject.getUserName(user)); } else { nameTextView.setText(""); } } long date = (long) avatarsArr.get(switchingToIndex).date * 1000; if (date != 0) { String dateString = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(new Date(date)), LocaleController.getInstance().formatterDay.format(new Date(date))); dateTextView.setText(dateString); } if (avatarsDialogId == UserConfig.getInstance(currentAccount).getClientUserId() && !avatarsArr.isEmpty()) { menuItem.showSubItem(gallery_menu_delete); } else { menuItem.hideSubItem(gallery_menu_delete); } if (isEvent) { actionBar.setTitle(LocaleController.getString("AttachPhoto", R.string.AttachPhoto)); } else { actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, switchingToIndex + 1, imagesArrLocations.size())); } menuItem.showSubItem(gallery_menu_save); menuItem.showSubItem(gallery_menu_scan); allowShare = true; shareButton.setVisibility(!videoPlayerControlVisible ? View.VISIBLE : View.GONE); if (shareButton.getVisibility() == View.VISIBLE) { menuItem.hideSubItem(gallery_menu_share); } else { menuItem.showSubItem(gallery_menu_share); } groupedPhotosListView.fillList(); } else if (!imagesArrLocals.isEmpty()) { if (index < 0 || index >= imagesArrLocals.size()) { return; } Object object = imagesArrLocals.get(index); int ttl = 0; boolean isFiltered = false; boolean isPainted = false; boolean isCropped = false; if (object instanceof TLRPC.BotInlineResult) { TLRPC.BotInlineResult botInlineResult = currentBotInlineResult = ((TLRPC.BotInlineResult) object); if (botInlineResult.document != null) { isVideo = MessageObject.isVideoDocument(botInlineResult.document); } else if (botInlineResult.content instanceof TLRPC.TL_webDocument) { isVideo = botInlineResult.type.equals("video"); } } else { boolean isAnimation = false; if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = ((MediaController.PhotoEntry) object); currentPathObject = photoEntry.path; isVideo = photoEntry.isVideo; } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage searchImage = (MediaController.SearchImage) object; currentPathObject = searchImage.getPathToAttach(); if (searchImage.type == 1) { isAnimation = true; } } if (isVideo) { if (!isCurrentVideo) { animateCaption = false; } isCurrentVideo = true; boolean isMuted = false; float start = 0.0f; float end = 1.0f; if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = ((MediaController.PhotoEntry) object); if (photoEntry.editedInfo != null) { isMuted = photoEntry.editedInfo.muted; start = photoEntry.editedInfo.start; end = photoEntry.editedInfo.end; } } processOpenVideo(currentPathObject, isMuted, start, end); if (isDocumentsPicker) { videoTimelineView.setVisibility(View.GONE); muteItem.setVisibility(View.GONE); muteItem.setTag(null); compressItem.setVisibility(View.GONE); } else { videoTimelineView.setVisibility(View.VISIBLE); muteItem.setVisibility(View.VISIBLE); muteItem.setTag(1); compressItem.setVisibility(View.VISIBLE); } cropItem.setVisibility(View.GONE); if (isDocumentsPicker || Build.VERSION.SDK_INT < 18) { tuneItem.setVisibility(View.GONE); tuneItem.setTag(null); paintItem.setVisibility(View.GONE); paintItem.setTag(null); } else { tuneItem.setVisibility(View.VISIBLE); tuneItem.setTag(1); paintItem.setVisibility(View.VISIBLE); paintItem.setTag(1); } rotateItem.setVisibility(View.GONE); } else { videoTimelineView.setVisibility(View.GONE); muteItem.setVisibility(View.GONE); muteItem.setTag(null); if (isCurrentVideo) { animateCaption = false; } isCurrentVideo = false; compressItem.setVisibility(View.GONE); if (isAnimation || sendPhotoType == SELECT_TYPE_QR || isDocumentsPicker) { paintItem.setVisibility(View.GONE); paintItem.setTag(null); cropItem.setVisibility(View.GONE); rotateItem.setVisibility(View.GONE); tuneItem.setVisibility(View.GONE); tuneItem.setTag(null); } else { if (sendPhotoType == 4 || sendPhotoType == 5) { paintItem.setVisibility(View.GONE); paintItem.setTag(null); tuneItem.setVisibility(View.GONE); tuneItem.setTag(null); } else { paintItem.setVisibility(View.VISIBLE); paintItem.setTag(1); tuneItem.setVisibility(View.VISIBLE); tuneItem.setTag(1); } cropItem.setVisibility(sendPhotoType != SELECT_TYPE_AVATAR ? View.VISIBLE : View.GONE); rotateItem.setVisibility(sendPhotoType != SELECT_TYPE_AVATAR ? View.GONE : View.VISIBLE); } actionBar.setSubtitle(null); } if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = ((MediaController.PhotoEntry) object); fromCamera = photoEntry.bucketId == 0 && photoEntry.dateTaken == 0 && imagesArrLocals.size() == 1; caption = photoEntry.caption; ttl = photoEntry.ttl; isFiltered = photoEntry.isFiltered; isPainted = photoEntry.isPainted; isCropped = photoEntry.isCropped; } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage searchImage = (MediaController.SearchImage) object; caption = searchImage.caption; ttl = searchImage.ttl; isFiltered = searchImage.isFiltered; isPainted = searchImage.isPainted; isCropped = searchImage.isCropped; } } if (bottomLayout.getVisibility() != View.GONE) { bottomLayout.setVisibility(View.GONE); } bottomLayout.setTag(null); if (fromCamera) { if (isVideo) { 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, switchingToIndex + 1, imagesArrLocals.size())); } if (parentChatActivity != null) { TLRPC.Chat chat = parentChatActivity.getCurrentChat(); if (chat != null) { actionBar.setTitle(chat.title); } else { TLRPC.User user = parentChatActivity.getCurrentUser(); if (user != null) { if (user.self) { actionBar.setTitle(LocaleController.getString("SavedMessages", R.string.SavedMessages)); } else { actionBar.setTitle(ContactsController.formatName(user.first_name, user.last_name)); } } } } if (sendPhotoType == 0 || sendPhotoType == 4 || (sendPhotoType == 2 || sendPhotoType == 5) && imagesArrLocals.size() > 1) { checkImageView.setChecked(placeProvider.isPhotoChecked(switchingToIndex), false); } updateCaptionTextForCurrentPhoto(object); PorterDuffColorFilter filter = new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN); timeItem.setColorFilter(ttl != 0 ? filter : null); paintItem.setColorFilter(isPainted ? filter : null); cropItem.setColorFilter(isCropped ? filter : null); tuneItem.setColorFilter(isFiltered ? filter : null); } setCurrentCaption(newMessageObject, caption, animateCaption); } private TLRPC.FileLocation getFileLocation(ImageLocation location) { if (location == null) { return null; } return location.location; } private void setImageIndex(int index) { setImageIndex(index, true, false); } private void setImageIndex(int index, boolean init, boolean animateCaption) { if (currentIndex == index || placeProvider == null) { return; } if (!init) { if (currentThumb != null) { currentThumb.release(); currentThumb = null; } } currentFileNames[0] = getFileName(index); currentFileNames[1] = getFileName(index + 1); currentFileNames[2] = getFileName(index - 1); placeProvider.willSwitchFromPhoto(currentMessageObject, getFileLocation(currentFileLocation), currentIndex); lastPhotoSetTime = SystemClock.elapsedRealtime(); int prevIndex = currentIndex; currentIndex = index; setIsAboutToSwitchToIndex(currentIndex, init, animateCaption); boolean isVideo = false; boolean sameImage = false; Uri videoPath = null; MediaController.SavedFilterState savedFilterState = null; currentPaintPath = null; currentMediaEntities = null; if (!imagesArr.isEmpty()) { if (currentIndex < 0 || currentIndex >= imagesArr.size()) { closePhoto(false, false); return; } MessageObject newMessageObject = imagesArr.get(currentIndex); sameImage = init && currentMessageObject != null && currentMessageObject.getId() == newMessageObject.getId(); currentMessageObject = newMessageObject; isVideo = newMessageObject.isVideo(); if (sharedMediaType == MediaDataController.MEDIA_FILE) { if (canZoom = newMessageObject.canPreviewDocument()) { menuItem.showSubItem(gallery_menu_save); menuItem.showSubItem(gallery_menu_scan); setDoubleTapEnabled(true); } else { menuItem.hideSubItem(gallery_menu_save); menuItem.hideSubItem(gallery_menu_scan); setDoubleTapEnabled(false); } } } else if (!secureDocuments.isEmpty()) { if (index < 0 || index >= secureDocuments.size()) { closePhoto(false, false); return; } currentSecureDocument = secureDocuments.get(index); } else if (!imagesArrLocations.isEmpty()) { if (index < 0 || index >= imagesArrLocations.size()) { closePhoto(false, false); return; } ImageLocation old = currentFileLocation; ImageLocation newLocation = imagesArrLocations.get(index); if (init && old != null && newLocation != null && old.location.local_id == newLocation.location.local_id && old.location.volume_id == newLocation.location.volume_id) { sameImage = true; } currentFileLocation = imagesArrLocations.get(index); } else if (!imagesArrLocals.isEmpty()) { if (index < 0 || index >= imagesArrLocals.size()) { closePhoto(false, false); return; } Object object = imagesArrLocals.get(index); if (object instanceof TLRPC.BotInlineResult) { TLRPC.BotInlineResult botInlineResult = currentBotInlineResult = ((TLRPC.BotInlineResult) object); if (botInlineResult.document != null) { currentPathObject = FileLoader.getPathToAttach(botInlineResult.document).getAbsolutePath(); isVideo = MessageObject.isVideoDocument(botInlineResult.document); } else if (botInlineResult.photo != null) { currentPathObject = FileLoader.getPathToAttach(FileLoader.getClosestPhotoSizeWithSize(botInlineResult.photo.sizes, AndroidUtilities.getPhotoSize())).getAbsolutePath(); } else if (botInlineResult.content instanceof TLRPC.TL_webDocument) { currentPathObject = botInlineResult.content.url; isVideo = botInlineResult.type.equals("video"); } } else { boolean isAnimation = false; if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry entry = ((MediaController.PhotoEntry) object); currentPathObject = entry.path; if (currentPathObject == null) { closePhoto(false, false); return; } isVideo = entry.isVideo; savedFilterState = entry.savedFilterState; currentPaintPath = entry.paintPath; currentAverageDuration = entry.averageDuration; currentMediaEntities = entry.mediaEntities; File file = new File(entry.path); videoPath = Uri.fromFile(file); if (isDocumentsPicker) { StringBuilder builder = new StringBuilder(); if (entry.width != 0 && entry.height != 0) { if (builder.length() > 0) { builder.append(", "); } builder.append(String.format(Locale.US, "%dx%d", entry.width, entry.height)); } if (entry.isVideo) { if (builder.length() > 0) { builder.append(", "); } builder.append(AndroidUtilities.formatShortDuration(entry.duration)); } if (entry.size != 0) { if (builder.length() > 0) { builder.append(", "); } builder.append(AndroidUtilities.formatFileSize(entry.size)); } docNameTextView.setText(file.getName()); docInfoTextView.setText(builder); } } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage searchImage = (MediaController.SearchImage) object; currentPathObject = searchImage.getPathToAttach(); savedFilterState = searchImage.savedFilterState; currentPaintPath = searchImage.paintPath; currentAverageDuration = searchImage.averageDuration; currentMediaEntities = searchImage.mediaEntities; } if (object instanceof MediaController.MediaEditState) { MediaController.MediaEditState state = (MediaController.MediaEditState) object; if (state.filterPath != null) { currentImagePath = state.filterPath; } else if (state.croppedPath != null) { currentImagePath = state.croppedPath; } else { currentImagePath = currentPathObject; } } } } if (currentPlaceObject != null) { if (animationInProgress == 0) { currentPlaceObject.imageReceiver.setVisible(true, true); } else { showAfterAnimation = currentPlaceObject; } } currentPlaceObject = placeProvider.getPlaceForPhoto(currentMessageObject, getFileLocation(currentFileLocation), currentIndex, false); 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); } pinchStartDistance = 0; pinchStartScale = 1; pinchCenterX = 0; pinchCenterY = 0; pinchStartX = 0; pinchStartY = 0; moveStartX = 0; moveStartY = 0; zooming = false; moving = false; paintViewTouched = 0; doubleTap = false; invalidCoords = false; canDragDown = true; changingPage = false; switchImageAfterAnimation = 0; if (sharedMediaType != MediaDataController.MEDIA_FILE) { canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && /*!isVideo && */photoProgressViews[0].backgroundState != 0); } updateMinMax(scale); releasePlayer(false); } if (isVideo && videoPath != null) { isStreaming = false; preparePlayer(videoPath, false, false, savedFilterState); } if (!imagesArrLocals.isEmpty()) { paintingOverlay.setVisibility(View.VISIBLE); paintingOverlay.setData(currentPaintPath, currentMediaEntities, isCurrentVideo, false); } else { paintingOverlay.setVisibility(View.GONE); currentPaintPath = null; currentMediaEntities = null; } if (prevIndex == -1) { setImages(); for (int a = 0; a < 3; a++) { checkProgress(a, false, false); } } else { checkProgress(0, true, false); if (prevIndex > currentIndex) { ImageReceiver temp = rightImage; rightImage = centerImage; centerImage = leftImage; leftImage = temp; PhotoProgressView tempProgress = photoProgressViews[0]; photoProgressViews[0] = photoProgressViews[2]; photoProgressViews[2] = tempProgress; setIndexToImage(leftImage, currentIndex - 1); updateAccessibilityOverlayVisibility(); checkProgress(1, true, false); checkProgress(2, true, false); } else if (prevIndex < currentIndex) { ImageReceiver temp = leftImage; leftImage = centerImage; centerImage = rightImage; rightImage = temp; PhotoProgressView tempProgress = photoProgressViews[0]; photoProgressViews[0] = photoProgressViews[1]; photoProgressViews[1] = tempProgress; setIndexToImage(rightImage, currentIndex + 1); updateAccessibilityOverlayVisibility(); checkProgress(1, true, false); checkProgress(2, true, false); } } } private void setCurrentCaption(MessageObject messageObject, final CharSequence caption, boolean animated) { if (needCaptionLayout) { if (captionTextViewSwitcher.getParent() != pickerView) { if (captionContainer != null) { captionContainer.removeView(captionTextViewSwitcher); } captionTextViewSwitcher.setMeasureAllChildren(false); pickerView.addView(captionTextViewSwitcher, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 76, 48)); } } else { if (captionScrollView == null) { captionScrollView = new CaptionScrollView(containerView.getContext()); captionContainer = new FrameLayout(containerView.getContext()); captionContainer.setClipChildren(false); captionScrollView.addView(captionContainer, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); containerView.addView(captionScrollView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); } if (captionTextViewSwitcher.getParent() != captionContainer) { pickerView.removeView(captionTextViewSwitcher); captionTextViewSwitcher.setMeasureAllChildren(true); captionContainer.addView(captionTextViewSwitcher, LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT); videoPreviewFrame.bringToFront(); } } final boolean isCaptionEmpty = TextUtils.isEmpty(caption); final boolean isCurrentCaptionEmpty = TextUtils.isEmpty(captionTextViewSwitcher.getCurrentView().getText()); TextView captionTextView = animated ? captionTextViewSwitcher.getNextView() : captionTextViewSwitcher.getCurrentView(); if (isCurrentVideo) { if (captionTextView.getMaxLines() != 1) { captionTextViewSwitcher.getCurrentView().setMaxLines(1); captionTextViewSwitcher.getNextView().setMaxLines(1); captionTextViewSwitcher.getCurrentView().setSingleLine(true); captionTextViewSwitcher.getNextView().setSingleLine(true); captionTextViewSwitcher.getCurrentView().setEllipsize(TextUtils.TruncateAt.END); captionTextViewSwitcher.getNextView().setEllipsize(TextUtils.TruncateAt.END); } } else { final int maxLines = captionTextView.getMaxLines(); if (maxLines == 1) { captionTextViewSwitcher.getCurrentView().setSingleLine(false); captionTextViewSwitcher.getNextView().setSingleLine(false); } final int newCount; if (needCaptionLayout) { newCount = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? 5 : 10; } else { newCount = Integer.MAX_VALUE; } if (maxLines != newCount) { captionTextViewSwitcher.getCurrentView().setMaxLines(newCount); captionTextViewSwitcher.getNextView().setMaxLines(newCount); captionTextViewSwitcher.getCurrentView().setEllipsize(null); captionTextViewSwitcher.getNextView().setEllipsize(null); } } captionTextView.setScrollX(0); dontChangeCaptionPosition = !needCaptionLayout && animated && isCaptionEmpty; boolean withTransition = false; if (!needCaptionLayout) { captionScrollView.dontChangeTopMargin = false; } if (animated && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { withTransition = true; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { TransitionManager.endTransitions(needCaptionLayout ? pickerView : captionScrollView); } if (needCaptionLayout) { final TransitionSet transitionSet = new TransitionSet(); transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER); transitionSet.addTransition(new ChangeBounds()); transitionSet.addTransition(new Fade(Fade.OUT)); transitionSet.addTransition(new Fade(Fade.IN)); transitionSet.setDuration(200); TransitionManager.beginDelayedTransition(pickerView, transitionSet); } else { final TransitionSet transition = new TransitionSet() .addTransition(new Fade(Fade.OUT) { @Override public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { final Animator animator = super.onDisappear(sceneRoot, view, startValues, endValues); if (!isCurrentCaptionEmpty && isCaptionEmpty && view == captionTextViewSwitcher) { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { captionScrollView.setVisibility(View.INVISIBLE); captionScrollView.backgroundAlpha = 1f; } }); ((ObjectAnimator) animator).addUpdateListener(animation -> { captionScrollView.backgroundAlpha = (float) animation.getAnimatedValue(); captionScrollView.invalidate(); }); } return animator; } }) .addTransition(new Fade(Fade.IN) { @Override public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { final Animator animator = super.onAppear(sceneRoot, view, startValues, endValues); if (isCurrentCaptionEmpty && !isCaptionEmpty && view == captionTextViewSwitcher) { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { captionScrollView.backgroundAlpha = 1f; } }); ((ObjectAnimator) animator).addUpdateListener(animation -> { captionScrollView.backgroundAlpha = (float) animation.getAnimatedValue(); captionScrollView.invalidate(); }); } return animator; } }) .setDuration(200); if (!isCurrentCaptionEmpty) { captionScrollView.dontChangeTopMargin = true; transition.addTransition(new Transition() { @Override public void captureStartValues(TransitionValues transitionValues) { if (transitionValues.view == captionScrollView) { transitionValues.values.put("scrollY", captionScrollView.getScrollY()); } } @Override public void captureEndValues(TransitionValues transitionValues) { if (transitionValues.view == captionTextViewSwitcher) { transitionValues.values.put("translationY", captionScrollView.getPendingMarginTopDiff()); } } @Override public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) { if (startValues.view == captionScrollView) { final ValueAnimator animator = ValueAnimator.ofInt((Integer) startValues.values.get("scrollY"), 0); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { captionTextViewSwitcher.getNextView().setText(null); captionScrollView.applyPendingTopMargin(); } @Override public void onAnimationStart(Animator animation) { captionScrollView.stopScrolling(); } }); animator.addUpdateListener(a -> captionScrollView.scrollTo(0, (Integer) a.getAnimatedValue())); return animator; } else if (endValues.view == captionTextViewSwitcher) { final int endValue = (int) endValues.values.get("translationY"); if (endValue != 0) { final ObjectAnimator animator = ObjectAnimator.ofFloat(captionTextViewSwitcher, View.TRANSLATION_Y, 0, endValue); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { captionTextViewSwitcher.setTranslationY(0); } }); return animator; } } return null; } }); } if (isCurrentCaptionEmpty && !isCaptionEmpty) { transition.addTarget(captionTextViewSwitcher); } TransitionManager.beginDelayedTransition(captionScrollView, transition); } } else { captionTextViewSwitcher.getCurrentView().setText(null); if (captionScrollView != null) { captionScrollView.scrollTo(0, 0); } } if (!isCaptionEmpty) { Theme.createChatResources(null, true); CharSequence str; if (messageObject != null && !messageObject.messageOwner.entities.isEmpty()) { Spannable spannableString = SpannableString.valueOf(caption.toString()); messageObject.addEntitiesToText(spannableString, true, false); if (messageObject.isVideo()) { MessageObject.addUrlsByPattern(messageObject.isOutOwner(), spannableString, false, 3, messageObject.getDuration(), false); } str = Emoji.replaceEmoji(spannableString, captionTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); } else { str = Emoji.replaceEmoji(new SpannableStringBuilder(caption), captionTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); } captionTextViewSwitcher.setTag(str); try { captionTextViewSwitcher.setText(str, animated); captionScrollView.updateTopMargin(); } catch (Exception e) { FileLog.e(e); } captionTextView.setScrollY(0); captionTextView.setTextColor(0xffffffff); boolean visible = isActionBarVisible && (bottomLayout.getVisibility() == View.VISIBLE || pickerView.getVisibility() == View.VISIBLE); captionTextViewSwitcher.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); } else { if (needCaptionLayout) { captionTextViewSwitcher.setText(LocaleController.getString("AddCaption", R.string.AddCaption), animated); captionTextViewSwitcher.getCurrentView().setTextColor(0xb2ffffff); captionTextViewSwitcher.setTag("empty"); captionTextViewSwitcher.setVisibility(View.VISIBLE); } else { captionTextViewSwitcher.setText(null, animated); captionTextViewSwitcher.getCurrentView().setTextColor(0xffffffff); captionTextViewSwitcher.setVisibility(View.INVISIBLE, !withTransition || isCurrentCaptionEmpty); captionTextViewSwitcher.setTag(null); } } } private void setCaptionHwLayerEnabled(boolean enabled) { if (captionHwLayerEnabled != enabled) { captionHwLayerEnabled = enabled; captionTextViewSwitcher.setLayerType(View.LAYER_TYPE_HARDWARE, null); captionTextViewSwitcher.getCurrentView().setLayerType(View.LAYER_TYPE_HARDWARE, null); captionTextViewSwitcher.getNextView().setLayerType(View.LAYER_TYPE_HARDWARE, null); } } private void checkProgress(int a, boolean scroll, boolean animated) { int index = currentIndex; if (a == 1) { index += 1; } else if (a == 2) { index -= 1; } if (currentFileNames[a] != null) { File f1 = null; File f2 = null; boolean isVideo = false; boolean canStream = false; MessageObject messageObject = null; if (currentMessageObject != null) { if (index < 0 || index >= imagesArr.size()) { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); return; } messageObject = imagesArr.get(index); if (sharedMediaType == MediaDataController.MEDIA_FILE && !messageObject.canPreviewDocument()) { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); return; } if (!TextUtils.isEmpty(messageObject.messageOwner.attachPath)) { f1 = new File(messageObject.messageOwner.attachPath); } if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageObject.messageOwner.media.webpage != null && messageObject.messageOwner.media.webpage.document == null) { TLObject fileLocation = getFileLocation(index, null); f2 = FileLoader.getPathToAttach(fileLocation, true); } else { f2 = FileLoader.getPathToMessage(messageObject.messageOwner); } if (messageObject.isVideo()) { canStream = SharedConfig.streamMedia && messageObject.canStreamVideo() && (int) messageObject.getDialogId() != 0; isVideo = true; } } else if (currentBotInlineResult != null) { if (index < 0 || index >= imagesArrLocals.size()) { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); return; } TLRPC.BotInlineResult botInlineResult = (TLRPC.BotInlineResult) imagesArrLocals.get(index); if (botInlineResult.type.equals("video") || MessageObject.isVideoDocument(botInlineResult.document)) { if (botInlineResult.document != null) { f1 = FileLoader.getPathToAttach(botInlineResult.document); } else if (botInlineResult.content instanceof TLRPC.TL_webDocument) { f1 = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(botInlineResult.content.url) + "." + ImageLoader.getHttpUrlExtension(botInlineResult.content.url, "mp4")); } isVideo = true; } else if (botInlineResult.document != null) { f1 = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), currentFileNames[a]); } else if (botInlineResult.photo != null) { f1 = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_IMAGE), currentFileNames[a]); } f2 = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), currentFileNames[a]); } else if (currentFileLocation != null) { if (index < 0 || index >= imagesArrLocations.size()) { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); return; } ImageLocation location = imagesArrLocations.get(index); f1 = FileLoader.getPathToAttach(location.location, avatarsDialogId != 0 || isEvent); } else if (currentSecureDocument != null) { if (index < 0 || index >= secureDocuments.size()) { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); return; } SecureDocument location = secureDocuments.get(index); f1 = FileLoader.getPathToAttach(location, true); } else if (currentPathObject != null) { f1 = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), currentFileNames[a]); f2 = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), currentFileNames[a]); } File f1Final = f1; File f2Final = f2; MessageObject messageObjectFinal = messageObject; boolean canStreamFinal = canStream; boolean isVideoFinal = isVideo; Utilities.globalQueue.postRunnable(() -> { boolean exists = false; if (f1Final != null) { exists = f1Final.exists(); } if (!exists && f2Final != null) { exists = f2Final.exists(); } if (!exists && a != 0 && messageObjectFinal != null && canStreamFinal) { if (DownloadController.getInstance(currentAccount).canDownloadMedia(messageObjectFinal.messageOwner) != 0) { if ((parentChatActivity == null || parentChatActivity.getCurrentEncryptedChat() == null) && !messageObjectFinal.shouldEncryptPhotoOrVideo()) { final TLRPC.Document document = messageObjectFinal.getDocument(); if (document != null) { FileLoader.getInstance(currentAccount).loadFile(document, messageObjectFinal, 0, 10); } } } } boolean existsFinal = exists; AndroidUtilities.runOnUIThread(() -> { if ((f1Final != null || f2Final != null) && (existsFinal || canStreamFinal)) { if (a != 0 || !isPlaying) { if (isVideoFinal && (!shouldMessageObjectAutoPlayed(messageObjectFinal) || a == 0 && playerWasPlaying)) { photoProgressViews[a].setBackgroundState(PROGRESS_PLAY, animated); } else { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); } } if (a == 0) { if (!existsFinal) { if (!FileLoader.getInstance(currentAccount).isLoadingFile(currentFileNames[a])) { menuItem.hideSubItem(gallery_menu_cancel_loading); } else { menuItem.showSubItem(gallery_menu_cancel_loading); } } else { menuItem.hideSubItem(gallery_menu_cancel_loading); } } } else { if (isVideoFinal) { if (!FileLoader.getInstance(currentAccount).isLoadingFile(currentFileNames[a])) { photoProgressViews[a].setBackgroundState(PROGRESS_LOAD, false); } else { photoProgressViews[a].setBackgroundState(PROGRESS_CANCEL, false); } } else { photoProgressViews[a].setBackgroundState(PROGRESS_EMPTY, animated); } Float progress = ImageLoader.getInstance().getFileProgress(currentFileNames[a]); if (progress == null) { progress = 0.0f; } photoProgressViews[a].setProgress(progress, false); } if (a == 0) { canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && photoProgressViews[0].backgroundState != 0); } }); }); } else { boolean isLocalVideo = false; if (!imagesArrLocals.isEmpty() && index >= 0 && index < imagesArrLocals.size()) { Object object = imagesArrLocals.get(index); if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = ((MediaController.PhotoEntry) object); isLocalVideo = photoEntry.isVideo; } } if (isLocalVideo) { photoProgressViews[a].setBackgroundState(PROGRESS_PLAY, animated); } else { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, animated); } } } public int getSelectiongLength() { return captionEditText != null ? captionEditText.getSelectionLength() : 0; } private void setIndexToImage(ImageReceiver imageReceiver, int index) { imageReceiver.setOrientation(0, false); if (!secureDocuments.isEmpty()) { if (index >= 0 && index < secureDocuments.size()) { Object object = secureDocuments.get(index); int size = (int) (AndroidUtilities.getPhotoSize() / AndroidUtilities.density); ImageReceiver.BitmapHolder placeHolder = null; if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; } if (placeHolder == null) { placeHolder = placeProvider.getThumbForPhoto(null, null, index); } SecureDocument document = secureDocuments.get(index); int imageSize = document.secureFile.size; imageReceiver.setImage(ImageLocation.getForSecureDocument(document), "d", null, null, placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, imageSize, null, null, 0); } } else if (!imagesArrLocals.isEmpty()) { if (index >= 0 && index < imagesArrLocals.size()) { Object object = imagesArrLocals.get(index); int size = (int) (AndroidUtilities.getPhotoSize() / AndroidUtilities.density); ImageReceiver.BitmapHolder 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; WebFile webDocument = null; ImageLocation videoThumb = null; TLRPC.PhotoSize photo = null; TLObject photoObject = null; int imageSize = 0; String filter = null; boolean isVideo = false; int cacheType = 0; if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; isVideo = photoEntry.isVideo; if (photoEntry.isVideo) { if (photoEntry.thumbPath != null) { path = photoEntry.thumbPath; } else { path = "vthumb://" + photoEntry.imageId + ":" + photoEntry.path; } } else { if (photoEntry.filterPath != null) { path = photoEntry.filterPath; } else if (photoEntry.croppedPath != null) { path = photoEntry.croppedPath; } else { imageReceiver.setOrientation(photoEntry.orientation, false); path = photoEntry.path; } filter = String.format(Locale.US, "%d_%d", size, size); } } else if (object instanceof TLRPC.BotInlineResult) { cacheType = 1; TLRPC.BotInlineResult botInlineResult = ((TLRPC.BotInlineResult) object); if (botInlineResult.type.equals("video") || MessageObject.isVideoDocument(botInlineResult.document)) { if (botInlineResult.document != null) { photo = FileLoader.getClosestPhotoSizeWithSize(botInlineResult.document.thumbs, 90); photoObject = botInlineResult.document; } else if (botInlineResult.thumb instanceof TLRPC.TL_webDocument) { webDocument = WebFile.createWithWebDocument(botInlineResult.thumb); } } else if (botInlineResult.type.equals("gif") && botInlineResult.document != null) { document = botInlineResult.document; imageSize = botInlineResult.document.size; TLRPC.TL_videoSize videoSize = MessageObject.getDocumentVideoThumb(botInlineResult.document); if (videoSize != null) { videoThumb = ImageLocation.getForDocument(videoSize, document); } filter = "d"; } else if (botInlineResult.photo != null) { TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(botInlineResult.photo.sizes, AndroidUtilities.getPhotoSize()); photo = sizeFull; photoObject = botInlineResult.photo; imageSize = sizeFull.size; filter = String.format(Locale.US, "%d_%d", size, size); } else if (botInlineResult.content instanceof TLRPC.TL_webDocument) { if (botInlineResult.type.equals("gif")) { filter = "d"; if (botInlineResult.thumb instanceof TLRPC.TL_webDocument && "video/mp4".equals(botInlineResult.thumb.mime_type)) { videoThumb = ImageLocation.getForWebFile(WebFile.createWithWebDocument(botInlineResult.thumb)); } } else { filter = String.format(Locale.US, "%d_%d", size, size); } webDocument = WebFile.createWithWebDocument(botInlineResult.content); } } else if (object instanceof MediaController.SearchImage) { cacheType = 1; MediaController.SearchImage photoEntry = (MediaController.SearchImage) object; if (photoEntry.photoSize != null) { photo = photoEntry.photoSize; photoObject = photoEntry.photo; imageSize = photoEntry.photoSize.size; } else if (photoEntry.filterPath != null) { path = photoEntry.filterPath; } else if (photoEntry.croppedPath != null) { path = photoEntry.croppedPath; } else if (photoEntry.document != null) { document = photoEntry.document; imageSize = photoEntry.document.size; } else { path = photoEntry.imageUrl; imageSize = photoEntry.size; } filter = "d"; } if (document != null) { TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); if (videoThumb != null) { imageReceiver.setImage(ImageLocation.getForDocument(document), "d", videoThumb, null, placeHolder == null ? ImageLocation.getForDocument(thumb, document) : null, String.format(Locale.US, "%d_%d", size, size), placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, imageSize, null, object, cacheType); } else { imageReceiver.setImage(ImageLocation.getForDocument(document), "d", placeHolder == null ? ImageLocation.getForDocument(thumb, document) : null, String.format(Locale.US, "%d_%d", size, size), placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, imageSize, null, object, cacheType); } } else if (photo != null) { imageReceiver.setImage(ImageLocation.getForObject(photo, photoObject), filter, placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, imageSize, null, object, cacheType); } else if (webDocument != null) { if (videoThumb != null) { imageReceiver.setImage(ImageLocation.getForWebFile(webDocument), filter, videoThumb, null, null, object, cacheType); } else { imageReceiver.setImage(ImageLocation.getForWebFile(webDocument), filter, placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : (isVideo && parentActivity != null ? parentActivity.getResources().getDrawable(R.drawable.nophotos) : null), null, object, cacheType); } } else { imageReceiver.setImage(path, filter, placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : (isVideo && parentActivity != null ? parentActivity.getResources().getDrawable(R.drawable.nophotos) : null), null, imageSize); } } else { imageReceiver.setImageBitmap((Bitmap) null); } } else { MessageObject messageObject; if (!imagesArr.isEmpty() && index >= 0 && index < imagesArr.size()) { messageObject = imagesArr.get(index); imageReceiver.setShouldGenerateQualityThumb(true); } else { messageObject = null; } if (messageObject != null) { if (messageObject.isVideo()) { if (messageObject.photoThumbs != null && !messageObject.photoThumbs.isEmpty()) { ImageReceiver.BitmapHolder placeHolder = null; if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; } TLRPC.PhotoSize thumbLocation = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 320); imageReceiver.setNeedsQualityThumb(thumbLocation.w < 100 && thumbLocation.h < 100); imageReceiver.setImage(null, null, placeHolder == null ? ImageLocation.getForObject(thumbLocation, messageObject.photoThumbsObject) : null, "b", placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, 0, null, messageObject, 1); } else { imageReceiver.setImageBitmap(parentActivity.getResources().getDrawable(R.drawable.photoview_placeholder)); } return; } else if (currentAnimation != null) { currentAnimation.setSecondParentView(containerView); imageReceiver.setImageBitmap(currentAnimation); return; } else if (sharedMediaType == MediaDataController.MEDIA_FILE) { if (messageObject.canPreviewDocument()) { TLRPC.Document document = messageObject.getDocument(); imageReceiver.setNeedsQualityThumb(true); ImageReceiver.BitmapHolder placeHolder = null; if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; } TLRPC.PhotoSize thumbLocation = messageObject != null ? FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 100) : null; int size = (int) (2048 / AndroidUtilities.density); imageReceiver.setImage(ImageLocation.getForDocument(document), String.format(Locale.US, "%d_%d", size, size), placeHolder == null ? ImageLocation.getForDocument(thumbLocation, document) : null, "b", placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, document.size, null, messageObject, 0); } else { OtherDocumentPlaceholderDrawable drawable = new OtherDocumentPlaceholderDrawable(parentActivity, containerView, messageObject); imageReceiver.setImageBitmap(drawable); } return; } } int[] size = new int[1]; ImageLocation imageLocation = getImageLocation(index, size); TLObject fileLocation = getFileLocation(index, size); if (imageLocation != null) { imageReceiver.setNeedsQualityThumb(true); ImageReceiver.BitmapHolder placeHolder = null; if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; } if (size[0] == 0) { size[0] = -1; } TLRPC.PhotoSize thumbLocation; TLObject photoObject; if (messageObject != null) { thumbLocation = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 100); photoObject = messageObject.photoThumbsObject; } else { thumbLocation = null; photoObject = null; } if (thumbLocation != null && thumbLocation == fileLocation) { thumbLocation = null; } boolean cacheOnly = messageObject != null && messageObject.isWebpage() || avatarsDialogId != 0 || isEvent; Object parentObject; ImageLocation videoThumb = null; if (messageObject != null) { parentObject = messageObject; if (sharedMediaType == MediaDataController.MEDIA_GIF) { TLRPC.Document document = messageObject.getDocument(); TLRPC.TL_videoSize videoSize = MessageObject.getDocumentVideoThumb(document); if (videoSize != null) { videoThumb = ImageLocation.getForDocument(videoSize, document); } } } else if (avatarsDialogId != 0) { if (avatarsDialogId > 0) { parentObject = MessagesController.getInstance(currentAccount).getUser(avatarsDialogId); } else { parentObject = MessagesController.getInstance(currentAccount).getChat(-avatarsDialogId); } } else { parentObject = null; } if (videoThumb != null) { imageReceiver.setImage(imageLocation, null, videoThumb, null, placeHolder == null ? ImageLocation.getForObject(thumbLocation, photoObject) : null, "b", placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, size[0], null, parentObject, cacheOnly ? 1 : 0); } else { imageReceiver.setImage(imageLocation, null, placeHolder == null ? ImageLocation.getForObject(thumbLocation, photoObject) : null, "b", placeHolder != null ? new BitmapDrawable(placeHolder.bitmap) : null, size[0], null, parentObject, cacheOnly ? 1 : 0); } } else { imageReceiver.setNeedsQualityThumb(true); if (size[0] == 0) { imageReceiver.setImageBitmap((Bitmap) null); } else { imageReceiver.setImageBitmap(parentActivity.getResources().getDrawable(R.drawable.photoview_placeholder)); } } } } public static boolean isShowingImage(MessageObject object) { boolean result = false; if (Instance != null) { result = !Instance.pipAnimationInProgress && Instance.isVisible && !Instance.disableShowCheck && object != null && Instance.currentMessageObject != null && Instance.currentMessageObject.getId() == object.getId() && Instance.currentMessageObject.getDialogId() == object.getDialogId(); } if (!result && PipInstance != null) { result = PipInstance.isVisible && !PipInstance.disableShowCheck && object != null && PipInstance.currentMessageObject != null && PipInstance.currentMessageObject.getId() == object.getId() && PipInstance.currentMessageObject.getDialogId() == object.getDialogId(); } return result; } public static boolean isPlayingMessageInPip(MessageObject object) { return PipInstance != null && object != null && PipInstance.currentMessageObject != null && PipInstance.currentMessageObject.getId() == object.getId() && PipInstance.currentMessageObject.getDialogId() == object.getDialogId(); } public static boolean isPlayingMessage(MessageObject object) { return Instance != null && !Instance.pipAnimationInProgress && Instance.isVisible && object != null && Instance.currentMessageObject != null && Instance.currentMessageObject.getId() == object.getId() && Instance.currentMessageObject.getDialogId() == object.getDialogId(); } public static boolean isShowingImage(TLRPC.FileLocation object) { boolean result = false; if (Instance != null) { result = Instance.isVisible && !Instance.disableShowCheck && object != null && Instance.currentFileLocation != null && object.local_id == Instance.currentFileLocation.location.local_id && object.volume_id == Instance.currentFileLocation.location.volume_id && object.dc_id == Instance.currentFileLocation.dc_id; } return result; } public static boolean isShowingImage(TLRPC.BotInlineResult object) { boolean result = false; if (Instance != null) { result = Instance.isVisible && !Instance.disableShowCheck && object != null && Instance.currentBotInlineResult != null && object.id == Instance.currentBotInlineResult.id; } return result; } public static boolean isShowingImage(String object) { boolean result = false; if (Instance != null) { result = Instance.isVisible && !Instance.disableShowCheck && object != null && object.equals(Instance.currentPathObject); } return result; } public void setParentChatActivity(ChatActivity chatActivity) { parentChatActivity = chatActivity; } public void setMaxSelectedPhotos(int value, boolean order) { maxSelectedPhotos = value; allowOrder = order; } public boolean openPhoto(final MessageObject messageObject, long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { return openPhoto(messageObject, null, null, null, null, null, 0, provider, null, dialogId, mergeDialogId, true); } public boolean openPhoto(final MessageObject messageObject, long dialogId, long mergeDialogId, final PhotoViewerProvider provider, boolean fullScreenVideo) { return openPhoto(messageObject, null, null, null, null, null, 0, provider, null, dialogId, mergeDialogId, fullScreenVideo); } public boolean openPhoto(final TLRPC.FileLocation fileLocation, final PhotoViewerProvider provider) { return openPhoto(null, fileLocation, null, null, null, null, 0, provider, null, 0, 0, true); } public boolean openPhoto(final TLRPC.FileLocation fileLocation, final ImageLocation imageLocation, final PhotoViewerProvider provider) { return openPhoto(null, fileLocation, imageLocation, null, null, null, 0, provider, null, 0, 0, true); } public boolean openPhoto(final ArrayList messages, final int index, long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { return openPhoto(messages.get(index), null, null, messages, null, null, index, provider, null, dialogId, mergeDialogId, true); } public boolean openPhoto(final ArrayList documents, final int index, final PhotoViewerProvider provider) { return openPhoto(null, null, null, null, documents, null, index, provider, null, 0, 0, true); } public boolean openPhotoForSelect(final ArrayList photos, final int index, int type, boolean documentsPicker, final PhotoViewerProvider provider, ChatActivity chatActivity) { sendPhotoType = type; isDocumentsPicker = documentsPicker; if (pickerViewSendButton != null) { FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) pickerViewSendButton.getLayoutParams(); if (sendPhotoType == 4 || sendPhotoType == 5) { pickerViewSendButton.setImageResource(R.drawable.attach_send); layoutParams2.bottomMargin = AndroidUtilities.dp(19); } else if (sendPhotoType == SELECT_TYPE_AVATAR || sendPhotoType == SELECT_TYPE_WALLPAPER || sendPhotoType == SELECT_TYPE_QR) { pickerViewSendButton.setImageResource(R.drawable.floating_check); pickerViewSendButton.setPadding(0, AndroidUtilities.dp(1), 0, 0); layoutParams2.bottomMargin = AndroidUtilities.dp(19); } else { pickerViewSendButton.setImageResource(R.drawable.attach_send); layoutParams2.bottomMargin = AndroidUtilities.dp(14); } pickerViewSendButton.setLayoutParams(layoutParams2); } return openPhoto(null, null, null, null, null, photos, index, provider, chatActivity, 0, 0, true); } 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; } private void setCropTranslations(boolean animated) { if (sendPhotoType != SELECT_TYPE_AVATAR) { return; } int bitmapWidth = centerImage.getBitmapWidth(); int bitmapHeight = centerImage.getBitmapHeight(); if (bitmapWidth == 0 || bitmapHeight == 0) { return; } float scaleX = (float) getContainerViewWidth() / (float) bitmapWidth; float scaleY = (float) getContainerViewHeight() / (float) bitmapHeight; float scaleFinal = Math.min(scaleX, scaleY); float minSide = Math.min(getContainerViewWidth(1), getContainerViewHeight(1)); float newScaleX = minSide / (float) bitmapWidth; float newScaleY = minSide / (float) bitmapHeight; float newScale = Math.max(newScaleX, newScaleY); if (animated) { animationStartTime = System.currentTimeMillis(); animateToX = getLeftInset() / 2 - getRightInset() / 2; if (currentEditMode == 2) { animateToY = AndroidUtilities.dp(92) - AndroidUtilities.dp(24 + 32); } else if (currentEditMode == 3) { animateToY = AndroidUtilities.dp(44) - AndroidUtilities.dp(24 + 32); } //animateToY = -AndroidUtilities.dp(24 + 32) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight / 2 : 0); animateToScale = newScale / scaleFinal; zoomAnimation = true; } else { animationStartTime = 0; translationX = getLeftInset() / 2 - getRightInset() / 2; translationY = -AndroidUtilities.dp(24 + 32) + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight / 2 : 0); scale = newScale / scaleFinal; updateMinMax(scale); } } private void setCropBitmap() { if (sendPhotoType != SELECT_TYPE_AVATAR) { return; } Bitmap bitmap = centerImage.getBitmap(); int orientation = centerImage.getOrientation(); if (bitmap == null) { bitmap = animatingImageView.getBitmap(); orientation = animatingImageView.getOrientation(); } if (bitmap != null) { photoCropView.setBitmap(bitmap, orientation, false, false, paintingOverlay); if (currentEditMode == 0) { setCropTranslations(false); } } } private void initCropView() { if (sendPhotoType != SELECT_TYPE_AVATAR) { return; } photoCropView.setBitmap(null, 0, false, false, null); photoCropView.onAppear(); photoCropView.setVisibility(View.VISIBLE); photoCropView.setAlpha(1.0f); photoCropView.onAppeared(); padImageForHorizontalInsets = true; } public boolean openPhoto(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ImageLocation imageLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, final int index, final PhotoViewerProvider provider, ChatActivity chatActivity, long dialogId, long mDialogId, boolean fullScreenVideo) { if (parentActivity == null || isVisible || provider == null && checkAnimation() || messageObject == null && fileLocation == null && messages == null && photos == null && documents == null && imageLocation == null) { return false; } final PlaceProviderObject object = provider.getPlaceForPhoto(messageObject, fileLocation, index, true); lastInsets = null; 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_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } else { windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } if (chatActivity != null && chatActivity.getCurrentEncryptedChat() != null && !NekoXConfig.disableFlagSecure) { windowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_SECURE; } else { windowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_SECURE; } windowLayoutParams.softInputMode = (useSmoothKeyboard ? WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN : 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(e); return false; } doneButtonPressed = false; parentChatActivity = chatActivity; actionBar.setTitle(LocaleController.formatString("Of", R.string.Of, 1, 1)); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.fileDidFailToLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.fileDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.FileLoadProgressChanged); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.mediaCountDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.mediaDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.dialogPhotosLoaded); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.filePreparingFailed); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.fileNewChunkAvailable); placeProvider = provider; mergeDialogId = mDialogId; currentDialogId = dialogId; selectedPhotosAdapter.notifyDataSetChanged(); if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } isVisible = true; togglePhotosListView(false, false); openedFullScreenVideo = !fullScreenVideo; if (openedFullScreenVideo) { toggleActionBar(false, false); } else { if (sendPhotoType == SELECT_TYPE_AVATAR) { createCropView(); toggleActionBar(false, false); } else { toggleActionBar(true, false); } } seekToProgressPending2 = 0; skipFirstBufferingProgress = false; playerInjected = false; if (object != null) { disableShowCheck = true; animationInProgress = 1; if (messageObject != null) { currentAnimation = object.allowTakeAnimation ? object.imageReceiver.getAnimation() : null; if (currentAnimation != null) { if (messageObject.isVideo()) { object.imageReceiver.setAllowStartAnimation(false); object.imageReceiver.stopAnimation(); if (MediaController.getInstance().isPlayingMessage(messageObject)) { seekToProgressPending2 = messageObject.audioProgress; } skipFirstBufferingProgress = injectingVideoPlayer == null && !FileLoader.getInstance(messageObject.currentAccount).isLoadingVideo(messageObject.getDocument(), true) && (currentAnimation.hasBitmap() || !FileLoader.getInstance(messageObject.currentAccount).isLoadingVideo(messageObject.getDocument(), false)); currentAnimation = null; } else if (messageObject.getWebPagePhotos(null, null).size() > 1) { currentAnimation = null; } } } onPhotoShow(messageObject, fileLocation, imageLocation, messages, documents, photos, index, object); if (sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.setVisibility(View.VISIBLE); photoCropView.setAlpha(0.0f); photoCropView.setFreeform(false); } final RectF drawRegion = object.imageReceiver.getDrawRegion(); float left = drawRegion.left; float top = drawRegion.top; int orientation = object.imageReceiver.getOrientation(); int animatedOrientation = object.imageReceiver.getAnimatedOrientation(); if (animatedOrientation != 0) { orientation = animatedOrientation; } final ClippingImageView[] animatingImageViews = getAnimatingImageViews(object); for (int i = 0; i < animatingImageViews.length; i++) { animatingImageViews[i].setAnimationValues(animationValues); animatingImageViews[i].setVisibility(View.VISIBLE); animatingImageViews[i].setRadius(object.radius); animatingImageViews[i].setOrientation(orientation); animatingImageViews[i].setImageBitmap(object.thumb); } initCropView(); if (sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.hideBackView(); photoCropView.setAspectRatio(1.0f); } final ViewGroup.LayoutParams layoutParams = animatingImageView.getLayoutParams(); layoutParams.width = (int) drawRegion.width(); layoutParams.height = (int) drawRegion.height(); if (layoutParams.width <= 0) { layoutParams.width = 100; } if (layoutParams.height <= 0) { layoutParams.height = 100; } for (int i = 0; i < animatingImageViews.length; i++) { if (animatingImageViews.length > 1) { animatingImageViews[i].setAlpha(0.0f); } else { animatingImageViews[i].setAlpha(1.0f); } animatingImageViews[i].setPivotX(0.0f); animatingImageViews[i].setPivotY(0.0f); animatingImageViews[i].setScaleX(object.scale); animatingImageViews[i].setScaleY(object.scale); animatingImageViews[i].setTranslationX(object.viewX + drawRegion.left * object.scale); animatingImageViews[i].setTranslationY(object.viewY + drawRegion.top * object.scale); animatingImageViews[i].setLayoutParams(layoutParams); } windowView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { if (animatingImageViews.length > 1) { animatingImageViews[1].setAlpha(1.0f); } windowView.getViewTreeObserver().removeOnPreDrawListener(this); float scaleX; float scaleY; float scale; float yPos; float xPos; if (sendPhotoType == SELECT_TYPE_AVATAR) { float statusBarHeight = (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); float measuredHeight = (float) photoCropView.getMeasuredHeight() - AndroidUtilities.dp(64) - statusBarHeight; float minSide = Math.min(photoCropView.getMeasuredWidth(), measuredHeight) - 2 * AndroidUtilities.dp(16); float centerX = photoCropView.getMeasuredWidth() / 2.0f; float centerY = statusBarHeight + measuredHeight / 2.0f; float left = centerX - (minSide / 2.0f); float top = centerY - (minSide / 2.0f); float right = centerX + (minSide / 2.0f); float bottom = centerY + (minSide / 2.0f); scaleX = (right - left) / layoutParams.width; scaleY = (bottom - top) / layoutParams.height; scale = Math.max(scaleX, scaleY); yPos = top + (bottom - top - layoutParams.height * scale) / 2; xPos = (windowView.getMeasuredWidth() - getLeftInset() - getRightInset() - layoutParams.width * scale) / 2.0f + getLeftInset(); } else { scaleX = (float) windowView.getMeasuredWidth() / layoutParams.width; scaleY = (float) (AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) / layoutParams.height; scale = Math.min(scaleX, scaleY); yPos = ((AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) - (layoutParams.height * scale)) / 2.0f; xPos = (windowView.getMeasuredWidth() - layoutParams.width * scale) / 2.0f; } int clipHorizontal = (int) Math.abs(left - object.imageReceiver.getImageX()); int clipVertical = (int) Math.abs(top - object.imageReceiver.getImageY()); int[] coords2 = new int[2]; object.parentView.getLocationInWindow(coords2); int clipTop = (int) (coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + top) + object.clipTopAddition); if (clipTop < 0) { clipTop = 0; } int clipBottom = (int) ((object.viewY + 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; int[] rad = animatingImageView.getRadius(); for (int a = 0; a < 4; a++) { animationValues[0][7 + a] = rad != null ? rad[a] : 0; } animationValues[0][11] = clipVertical * object.scale; animationValues[0][12] = clipHorizontal * object.scale; 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; animationValues[1][8] = 0; animationValues[1][9] = 0; animationValues[1][10] = 0; animationValues[1][11] = 0; animationValues[1][12] = 0; for (int i = 0; i < animatingImageViews.length; i++) { animatingImageViews[i].setAnimationProgress(0); } backgroundDrawable.setAlpha(0); containerView.setAlpha(0); animationEndRunnable = () -> { if (containerView == null || windowView == null) { return; } if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_NONE, null); } animationInProgress = 0; transitionAnimationStartTime = 0; setImages(); setCropBitmap(); if (sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.showBackView(); } containerView.invalidate(); for (int i = 0; i < animatingImageViews.length; i++) { animatingImageViews[i].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 = (useSmoothKeyboard ? WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN : WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) | WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; WindowManager wm1 = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); wm1.updateViewLayout(windowView, windowLayoutParams); windowView.setFocusable(true); containerView.setFocusable(true); } }; if (!openedFullScreenVideo) { final AnimatorSet animatorSet = new AnimatorSet(); ArrayList animators = new ArrayList<>((sendPhotoType == SELECT_TYPE_AVATAR ? 3 : 2) + animatingImageViews.length + (animatingImageViews.length > 1 ? 1 : 0)); for (int i = 0; i < animatingImageViews.length; i++) { animators.add(ObjectAnimator.ofFloat(animatingImageViews[i], AnimationProperties.CLIPPING_IMAGE_VIEW_PROGRESS, 0.0f, 1.0f)); } if (animatingImageViews.length > 1) { animators.add(ObjectAnimator.ofFloat(animatingImageView, View.ALPHA, 0f, 1f)); } animators.add(ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0, 255)); animators.add(ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f, 1.0f)); if (sendPhotoType == SELECT_TYPE_AVATAR) { animators.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0, 1.0f)); } animatorSet.playTogether(animators); animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { AndroidUtilities.runOnUIThread(() -> { NotificationCenter.getInstance(currentAccount).onAnimationFinish(transitionIndex); if (animationEndRunnable != null) { animationEndRunnable.run(); animationEndRunnable = null; } setCaptionHwLayerEnabled(true); }); } }); if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } setCaptionHwLayerEnabled(false); transitionAnimationStartTime = System.currentTimeMillis(); AndroidUtilities.runOnUIThread(() -> { transitionIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(transitionIndex, new int[]{NotificationCenter.dialogsNeedReload, NotificationCenter.closeChats, NotificationCenter.mediaCountDidLoad, NotificationCenter.mediaDidLoad, NotificationCenter.dialogPhotosLoaded}); animatorSet.start(); }); } else { if (animationEndRunnable != null) { animationEndRunnable.run(); animationEndRunnable = null; } containerView.setAlpha(1.0f); backgroundDrawable.setAlpha(255); for (int i = 0; i < animatingImageViews.length; i++) { animatingImageViews[i].setAnimationProgress(1.0f); } if (sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.setAlpha(1.0f); } } backgroundDrawable.drawRunnable = () -> { disableShowCheck = false; object.imageReceiver.setVisible(false, true); }; return 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 = (useSmoothKeyboard ? WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN : 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, imageLocation, messages, documents, photos, index, object); initCropView(); setCropBitmap(); } AccessibilityManager am = (AccessibilityManager) parentActivity.getSystemService(Context.ACCESSIBILITY_SERVICE); if (am.isTouchExplorationEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain(); event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT); event.getText().add(LocaleController.getString("AccDescrPhotoViewer", R.string.AccDescrPhotoViewer)); am.sendAccessibilityEvent(event); } return true; } public void injectVideoPlayerToMediaController() { if (videoPlayer.isPlaying()) { if (playerLooping) { videoPlayer.setLooping(false); } MediaController.getInstance().injectVideoPlayer(videoPlayer, currentMessageObject); videoPlayer = null; } } public void closePhoto(boolean animated, boolean fromEditMode) { if (!fromEditMode && currentEditMode != 0) { if (currentEditMode == 3 && photoPaintView != null) { photoPaintView.maybeShowDismissalAlert(this, parentActivity, () -> switchToEditMode(0)); return; } switchToEditMode(0); return; } if (qualityChooseView != null && qualityChooseView.getTag() != null) { qualityPicker.cancelButton.callOnClick(); return; } openedFullScreenVideo = false; try { if (visibleDialog != null) { visibleDialog.dismiss(); visibleDialog = null; } } catch (Exception e) { FileLog.e(e); } if (Build.VERSION.SDK_INT >= 21 && containerView != null) { AndroidUtilities.cancelRunOnUIThread(updateContainerFlagsRunnable); updateContainerFlags(true); } 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); } else if (currentEditMode == 3) { photoPaintView.shutdown(); containerView.removeView(photoPaintView); photoPaintView = null; } currentEditMode = 0; } else if (sendPhotoType == SELECT_TYPE_AVATAR) { photoCropView.setVisibility(View.GONE); } if (parentActivity == null || !isInline && !isVisible || checkAnimation() || placeProvider == null) { return; } if (captionEditText.hideActionMode() && !fromEditMode) { return; } if (!doneButtonPressed && !imagesArrLocals.isEmpty() && currentIndex >= 0 && currentIndex < imagesArrLocals.size()) { Object entry = imagesArrLocals.get(currentIndex); if (entry instanceof MediaController.MediaEditState) { ((MediaController.MediaEditState) entry).editedInfo = getCurrentVideoEditedInfo(); } } final PlaceProviderObject object = placeProvider.getPlaceForPhoto(currentMessageObject, getFileLocation(currentFileLocation), currentIndex, true); if (videoPlayer != null && object != null) { AnimatedFileDrawable animation = object.imageReceiver.getAnimation(); if (animation != null) { if (textureUploaded) { Bitmap bitmap = animation.getAnimatedBitmap(); if (bitmap != null) { try { Bitmap src = videoTextureView.getBitmap(bitmap.getWidth(), bitmap.getHeight()); Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(src, 0, 0, null); src.recycle(); } catch (Throwable e) { FileLog.e(e); } } } if (currentMessageObject != null) { long startTime = animation.getStartTime(); long seekTo = videoPlayer.getCurrentPosition() + (startTime > 0 ? startTime : 0); animation.seekTo(seekTo, !FileLoader.getInstance(currentMessageObject.currentAccount).isLoadingVideo(currentMessageObject.getDocument(), true)); } object.imageReceiver.setAllowStartAnimation(true); object.imageReceiver.startAnimation(); } } releasePlayer(true); captionEditText.onDestroy(); parentChatActivity = null; removeObservers(); isActionBarVisible = false; if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } if (isInline) { isInline = false; animationInProgress = 0; onPhotoClosed(object); containerView.setScaleX(1.0f); containerView.setScaleY(1.0f); } else { if (animated) { final ClippingImageView[] animatingImageViews = getAnimatingImageViews(object); for (int i = 0; i < animatingImageViews.length; i++) { animatingImageViews[i].setAnimationValues(animationValues); animatingImageViews[i].setVisibility(View.VISIBLE); } animationInProgress = 3; containerView.invalidate(); AnimatorSet animatorSet = new AnimatorSet(); final ViewGroup.LayoutParams layoutParams = animatingImageView.getLayoutParams(); RectF drawRegion = null; if (object != null) { drawRegion = object.imageReceiver.getDrawRegion(); layoutParams.width = (int) drawRegion.width(); layoutParams.height = (int) drawRegion.height(); int orientation = object.imageReceiver.getOrientation(); int animatedOrientation = object.imageReceiver.getAnimatedOrientation(); if (animatedOrientation != 0) { orientation = animatedOrientation; } for (int i = 0; i < animatingImageViews.length; i++) { animatingImageViews[i].setOrientation(orientation); animatingImageViews[i].setImageBitmap(object.thumb); } } else { layoutParams.width = (int) centerImage.getImageWidth(); layoutParams.height = (int) centerImage.getImageHeight(); for (int i = 0; i < animatingImageViews.length; i++) { animatingImageViews[i].setOrientation(centerImage.getOrientation()); animatingImageViews[i].setImageBitmap(centerImage.getBitmapSafe()); } } if (layoutParams.width <= 0) { layoutParams.width = 100; } if (layoutParams.height <= 0) { layoutParams.height = 100; } float scaleX = (float) windowView.getMeasuredWidth() / layoutParams.width; float scaleY = (float) (AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) / layoutParams.height; float scale2 = Math.min(scaleX, scaleY); float width = layoutParams.width * scale * scale2; float height = layoutParams.height * scale * scale2; float xPos = (windowView.getMeasuredWidth() - width) / 2.0f; float yPos = ((AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) - height) / 2.0f; for (int i = 0; i < animatingImageViews.length; i++) { animatingImageViews[i].setLayoutParams(layoutParams); animatingImageViews[i].setTranslationX(xPos + translationX); animatingImageViews[i].setTranslationY(yPos + translationY); animatingImageViews[i].setScaleX(scale * scale2); animatingImageViews[i].setScaleY(scale * scale2); } if (object != null) { object.imageReceiver.setVisible(false, true); int clipHorizontal = (int) Math.abs(drawRegion.left - object.imageReceiver.getImageX()); int clipVertical = (int) Math.abs(drawRegion.top - object.imageReceiver.getImageY()); int[] coords2 = new int[2]; object.parentView.getLocationInWindow(coords2); int clipTop = (int) (coords2[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight) - (object.viewY + drawRegion.top) + object.clipTopAddition); if (clipTop < 0) { clipTop = 0; } int clipBottom = (int) ((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[0][8] = 0; animationValues[0][9] = 0; animationValues[0][10] = 0; animationValues[0][11] = 0; animationValues[0][12] = 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; for (int a = 0; a < 4; a++) { animationValues[1][7 + a] = object.radius != null ? object.radius[a] : 0; } animationValues[1][11] = clipVertical * object.scale; animationValues[1][12] = clipHorizontal * object.scale; ArrayList animators = new ArrayList<>((sendPhotoType == SELECT_TYPE_AVATAR ? 3 : 2) + animatingImageViews.length + (animatingImageViews.length > 1 ? 1 : 0)); for (int i = 0; i < animatingImageViews.length; i++) { animators.add(ObjectAnimator.ofFloat(animatingImageViews[i], AnimationProperties.CLIPPING_IMAGE_VIEW_PROGRESS, 0.0f, 1.0f)); } if (animatingImageViews.length > 1) { animators.add(ObjectAnimator.ofFloat(animatingImageView, View.ALPHA, 0f)); } animators.add(ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0)); animators.add(ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f)); if (sendPhotoType == SELECT_TYPE_AVATAR) { animators.add(ObjectAnimator.ofFloat(photoCropView, View.ALPHA, 0.0f)); } animatorSet.playTogether(animators); } else { int h = (AndroidUtilities.displaySize.y + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)); animatorSet.playTogether( ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0), ObjectAnimator.ofFloat(animatingImageView, View.ALPHA, 0.0f), ObjectAnimator.ofFloat(animatingImageView, View.TRANSLATION_Y, translationY >= 0 ? h : -h), ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f) ); } animationEndRunnable = () -> { if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_NONE, null); } animationInProgress = 0; onPhotoClosed(object); }; animatorSet.setDuration(200); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { AndroidUtilities.runOnUIThread(() -> { 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, View.SCALE_X, 0.9f), ObjectAnimator.ofFloat(containerView, View.SCALE_Y, 0.9f), ObjectAnimator.ofInt(backgroundDrawable, AnimationProperties.COLOR_DRAWABLE_ALPHA, 0), ObjectAnimator.ofFloat(containerView, View.ALPHA, 0.0f) ); animationInProgress = 2; animationEndRunnable = () -> { 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 AnimatorListenerAdapter() { @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 != null && !placeProvider.canScrollAway()) { placeProvider.cancelButtonPressed(); } } } private ClippingImageView[] getAnimatingImageViews(PlaceProviderObject object) { final boolean hasSecondAnimatingImageView = !AndroidUtilities.isTablet() && object != null && object.animatingImageView != null; final ClippingImageView[] animatingImageViews = new ClippingImageView[1 + (hasSecondAnimatingImageView ? 1 : 0)]; animatingImageViews[0] = animatingImageView; if (hasSecondAnimatingImageView) { animatingImageViews[1] = object.animatingImageView; object.animatingImageView.setAdditionalTranslationY(object.animatingImageViewYOffset); } return animatingImageViews; } private void removeObservers() { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileDidFailToLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.FileLoadProgressChanged); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.mediaCountDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.mediaDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.dialogPhotosLoaded); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.filePreparingFailed); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileNewChunkAvailable); ConnectionsManager.getInstance(currentAccount).cancelRequestsForGuid(classGuid); } public void destroyPhotoViewer() { if (parentActivity == null || windowView == null) { return; } if (pipVideoView != null) { pipVideoView.close(); pipVideoView = null; } removeObservers(); releasePlayer(false); try { if (windowView.getParent() != null) { WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); wm.removeViewImmediate(windowView); } windowView = null; } catch (Exception e) { FileLog.e(e); } if (currentThumb != null) { currentThumb.release(); currentThumb = null; } animatingImageView.setImageBitmap(null); if (captionEditText != null) { captionEditText.onDestroy(); } if (this == PipInstance) { PipInstance = null; } else { Instance = null; } } private void onPhotoClosed(PlaceProviderObject object) { isVisible = false; disableShowCheck = true; currentMessageObject = null; currentBotInlineResult = null; currentFileLocation = null; currentSecureDocument = null; currentPathObject = null; if (videoPlayerControlFrameLayout != null) { setVideoPlayerControlVisible(false, false); } if (captionScrollView != null) { captionScrollView.reset(); } if (groupedPhotosListView != null) { groupedPhotosListView.reset(); } sendPhotoType = 0; isDocumentsPicker = false; if (currentThumb != null) { currentThumb.release(); currentThumb = null; } parentAlert = null; if (currentAnimation != null) { currentAnimation.setSecondParentView(null); currentAnimation = null; } for (int a = 0; a < 3; a++) { if (photoProgressViews[a] != null) { photoProgressViews[a].setBackgroundState(PROGRESS_NONE, false); } } requestVideoPreview(0); if (videoTimelineView != null) { videoTimelineView.destroy(); } centerImage.setImageBitmap((Bitmap) null); leftImage.setImageBitmap((Bitmap) null); rightImage.setImageBitmap((Bitmap) null); containerView.post(() -> { animatingImageView.setImageBitmap(null); if (object != null && !AndroidUtilities.isTablet() && object.animatingImageView != null) { object.animatingImageView.setImageBitmap(null); } try { if (windowView.getParent() != null) { WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); wm.removeView(windowView); } } catch (Exception e) { FileLog.e(e); } }); if (placeProvider != null) { placeProvider.willHidePhotoViewer(); } groupedPhotosListView.clear(); placeProvider = null; selectedPhotosAdapter.notifyDataSetChanged(); disableShowCheck = false; videoCutStart = 0; videoCutEnd = 1f; if (object != null) { object.imageReceiver.setVisible(true, true); } } private void redraw(final int count) { if (count < 6) { if (containerView != null) { containerView.invalidate(); AndroidUtilities.runOnUIThread(() -> redraw(count + 1), 100); } } } public void onResume() { redraw(0); //workaround for camera bug if (videoPlayer != null) { videoPlayer.seekTo(videoPlayer.getCurrentPosition() + 1); if (playerLooping) { videoPlayer.setLooping(true); } } if (photoPaintView != null) { photoPaintView.onResume(); } } public void onConfigurationChanged(Configuration newConfig) { if (pipVideoView != null) { pipVideoView.onConfigurationChanged(); } } public void onPause() { if (currentAnimation != null) { closePhoto(false, false); return; } if (lastTitle != null) { closeCaptionEnter(true); } if (videoPlayer != null && playerLooping) { videoPlayer.setLooping(false); } } public boolean isVisible() { return isVisible && placeProvider != null; } private void updateMinMax(float scale) { if (currentEditMode == 3 && aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == View.VISIBLE && textureUploaded) { scale *= Math.min(getContainerViewWidth() / (float) videoTextureView.getMeasuredWidth(), getContainerViewHeight() / (float) videoTextureView.getMeasuredHeight()); } 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; } } private int getAdditionX() { if (currentEditMode != 0 && currentEditMode != 3) { return AndroidUtilities.dp(14); } return 0; } private int getAdditionY() { if (currentEditMode == 3) { return AndroidUtilities.dp(8) + (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) { return getContainerViewHeight(false, mode); } private int getContainerViewHeight(boolean trueHeight, int mode) { int height; if (trueHeight) { height = containerView.getMeasuredHeight(); } else { height = AndroidUtilities.displaySize.y; if (mode == 0 && Build.VERSION.SDK_INT >= 21) { height += AndroidUtilities.statusBarHeight; } } if (mode == 1) { height -= AndroidUtilities.dp(48 + 32 + 64); } else if (mode == 2) { height -= AndroidUtilities.dp(154 + 60); } else if (mode == 3) { height -= AndroidUtilities.dp(48) + ActionBar.getCurrentActionBarHeight(); } return height; } private boolean onTouchEvent(MotionEvent ev) { if (currentEditMode == 3 && animationStartTime != 0 && (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN)) { if (ev.getPointerCount() >= 2) { cancelMoveZoomAnimation(); } else { return true; } } if (animationInProgress != 0 || animationStartTime != 0) { return false; } if (currentEditMode == 2) { photoFilterView.onTouch(ev); return true; } else if (currentEditMode == 1 || currentEditMode != 3 && sendPhotoType == SELECT_TYPE_AVATAR) { return true; } if (captionEditText.isPopupShowing() || captionEditText.isKeyboardVisible()) { if (ev.getAction() == MotionEvent.ACTION_UP) { closeCaptionEnter(true); } return true; } if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR && ev.getPointerCount() == 1 && gestureDetector.onTouchEvent(ev)) { if (doubleTap) { doubleTap = false; moving = false; zooming = false; checkMinMax(false); return true; } } if (tooltip != null) { tooltip.hide(); } if (ev.getActionMasked() == MotionEvent.ACTION_DOWN || ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { discardTap = false; if (!scroller.isFinished()) { scroller.abortAnimation(); } if (!draggingDown && !changingPage) { if (canZoom && ev.getPointerCount() == 2) { if (paintViewTouched == 1) { MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); photoPaintView.onTouch(event); event.recycle(); paintViewTouched = 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 (currentEditMode == 3) { moveStartX = pinchCenterX; moveStartY = pinchCenterY; draggingDown = false; canDragDown = false; } hidePressedDrawables(); if (velocityTracker != null) { velocityTracker.clear(); } } else if (ev.getPointerCount() == 1) { if (currentEditMode == 3) { if (paintViewTouched == 0) { photoPaintView.getHitRect(hitRect); if (hitRect.contains((int) ev.getX(), (int) ev.getY())) { MotionEvent event = MotionEvent.obtain(ev); event.offsetLocation(-photoPaintView.getX(), -photoPaintView.getY()); photoPaintView.onTouch(event); event.recycle(); paintViewTouched = 1; } } } else { moveStartX = ev.getX(); dragY = moveStartY = ev.getY(); draggingDown = false; canDragDown = true; if (velocityTracker != null) { velocityTracker.clear(); } } } } } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) { if (canZoom && ev.getPointerCount() == 2 && !draggingDown && zooming && !changingPage) { discardTap = true; if (currentEditMode == 3) { float newPinchCenterX = (ev.getX(0) + ev.getX(1)) / 2.0f; float newPinchCenterY = (ev.getY(0) + ev.getY(1)) / 2.0f; float moveDx = moveStartX - newPinchCenterX; float moveDy = moveStartY - newPinchCenterY; moveStartX = newPinchCenterX; moveStartY = newPinchCenterY; if (translationX < minX || translationX > maxX) { moveDx /= 3.0f; } if (translationY < minY || translationY > maxY) { moveDy /= 3.0f; } pinchStartX = (pinchCenterX - getContainerViewWidth() / 2) - ((pinchCenterX - getContainerViewWidth() / 2) - translationX) / (scale / pinchStartScale) - moveDx; pinchStartY = (pinchCenterY - getContainerViewHeight() / 2) - ((pinchCenterY - getContainerViewHeight() / 2) - translationY) / (scale / pinchStartScale) - moveDy; pinchCenterX = newPinchCenterX; pinchCenterY = newPinchCenterY; } 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); if (currentEditMode == 3) { photoPaintView.setTransform(scale, translationX, translationY); } updateMinMax(scale); containerView.invalidate(); } else if (ev.getPointerCount() == 1) { if (paintViewTouched == 1) { MotionEvent event = MotionEvent.obtain(ev); event.offsetLocation(-photoPaintView.getX(), -photoPaintView.getY()); photoPaintView.onTouch(event); event.recycle(); return true; } if (velocityTracker != null) { velocityTracker.addMovement(ev); } float dx = Math.abs(ev.getX() - moveStartX); float dy = Math.abs(ev.getY() - dragY); if (dx > touchSlop || dy > touchSlop) { discardTap = true; hidePressedDrawables(); if (qualityChooseView != null && qualityChooseView.getVisibility() == View.VISIBLE) { return true; } } if (placeProvider.canScrollAway() && currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR && canDragDown && !draggingDown && scale == 1 && dy >= AndroidUtilities.dp(30) && dy / 2 > dx) { draggingDown = true; hidePressedDrawables(); moving = false; dragY = ev.getY(); if (isActionBarVisible && containerView.getTag() != null) { toggleActionBar(false, true); } else if (pickerView.getVisibility() == View.VISIBLE) { toggleActionBar(false, true); togglePhotosListView(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; hidePressedDrawables(); } moveStartX = ev.getX(); moveStartY = ev.getY(); updateMinMax(scale); if (translationX < minX && (currentEditMode != 0 || !rightImage.hasImageSet()) || translationX > maxX && (currentEditMode != 0 || !leftImage.hasImageSet())) { moveDx /= 3.0f; } if (maxY == 0 && minY == 0 && currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { 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; } if (currentEditMode == 3) { photoPaintView.setTransform(scale, translationX, translationY); } 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 (paintViewTouched == 1) { if (photoPaintView != null) { MotionEvent event = MotionEvent.obtain(ev); event.offsetLocation(-photoPaintView.getX(), -photoPaintView.getY()); photoPaintView.onTouch(event); event.recycle(); } paintViewTouched = 0; return true; } paintViewTouched = 0; 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); if (currentEditMode == 3) { 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, false); } } zooming = false; moving = 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 && sendPhotoType != SELECT_TYPE_AVATAR) { if ((translationX < minX - getContainerViewWidth() / 3 || velocity < -AndroidUtilities.dp(650)) && rightImage.hasImageSet()) { goToNext(); return true; } if ((translationX > maxX + getContainerViewWidth() / 3 || velocity > AndroidUtilities.dp(650)) && leftImage.hasImageSet()) { 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 cancelMoveZoomAnimation() { if (imageMoveAnimation == null) { return; } float ts = scale + (animateToScale - scale) * animationValue; float tx = translationX + (animateToX - translationX) * animationValue; float ty = translationY + (animateToY - translationY) * animationValue; imageMoveAnimation.cancel(); scale = ts; translationX = tx; translationY = ty; animationStartTime = 0; updateMinMax(scale); zoomAnimation = false; containerView.invalidate(); } 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, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1) ); imageMoveAnimation.setInterpolator(interpolator); imageMoveAnimation.setDuration(duration); imageMoveAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { imageMoveAnimation = null; containerView.invalidate(); } }); imageMoveAnimation.start(); } @Keep public void setAnimationValue(float value) { animationValue = value; containerView.invalidate(); } @Keep public float getAnimationValue() { return animationValue; } private void switchToNextIndex(int add, boolean init) { if (currentMessageObject != null) { releasePlayer(false); FileLoader.getInstance(currentAccount).cancelLoadFile(currentMessageObject.getDocument()); } playerAutoStarted = false; setImageIndex(currentIndex + add, init, true); if (shouldMessageObjectAutoPlayed(currentMessageObject)) { playerAutoStarted = true; onActionClick(true); checkProgress(0, false, true); } } private boolean shouldMessageObjectAutoPlayed(MessageObject messageObject) { return messageObject != null && messageObject.isVideo() && (messageObject.mediaExists || messageObject.attachPathExists || messageObject.canStreamVideo() && SharedConfig.streamMedia) && SharedConfig.autoplayVideo; } @SuppressLint({"NewApi", "DrawAllocation"}) private void onDraw(Canvas canvas) { if (animationInProgress == 1 || animationInProgress == 3 || !isVisible && animationInProgress != 2 && !pipAnimationInProgress) { return; } if (padImageForHorizontalInsets) { canvas.save(); canvas.translate(getLeftInset() / 2 - getRightInset() / 2, 0); } float currentTranslationY; float currentTranslationX; float currentScale; float aty = -1; long newUpdateTime = System.currentTimeMillis(); long dt = newUpdateTime - videoCrossfadeAlphaLastTime; if (dt > 20) { dt = 17; } videoCrossfadeAlphaLastTime = newUpdateTime; 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 (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; 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) { openedFullScreenVideo = false; if (!imagesArrLocals.isEmpty() && currentIndex >= 0 && currentIndex < imagesArrLocals.size()) { Object object = imagesArrLocals.get(currentIndex); if (object instanceof MediaController.MediaEditState) { ((MediaController.MediaEditState) object).editedInfo = getCurrentVideoEditedInfo(); } } if (switchImageAfterAnimation == 1) { AndroidUtilities.runOnUIThread(() -> switchToNextIndex(1, false)); } else if (switchImageAfterAnimation == 2) { AndroidUtilities.runOnUIThread(() -> switchToNextIndex(-1, false)); } switchImageAfterAnimation = 0; } currentScale = scale; currentTranslationY = translationY; currentTranslationX = translationX; if (!moving) { aty = translationY; } } if (currentEditMode == 3) { photoPaintView.setTransform(currentScale, currentTranslationX, currentTranslationY); } if (animationInProgress != 2 && !pipAnimationInProgress && !isInline) { if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR && 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); } } sideImage = null; if (currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { if (scale >= 1.0f && !zoomAnimation && !zooming) { if (currentTranslationX > maxX + AndroidUtilities.dp(5)) { sideImage = leftImage; } else if (currentTranslationX < minX - AndroidUtilities.dp(5)) { sideImage = rightImage; } else { groupedPhotosListView.setMoveProgress(0.0f); } } changingPage = sideImage != null; } if (sideImage == rightImage) { float translateX = currentTranslationX; float scaleDiff = 0; float alpha = 1; if (!zoomAnimation && translateX < minX) { alpha = Math.min(1.0f, (minX - translateX) / getContainerViewWidth()); scaleDiff = (1.0f - alpha) * 0.3f; translateX = -getContainerViewWidth() - AndroidUtilities.dp(30) / 2; } if (sideImage.hasBitmapImage()) { canvas.save(); canvas.translate(getContainerViewWidth() / 2, getContainerViewHeight() / 2); canvas.translate(getContainerViewWidth() + AndroidUtilities.dp(30) / 2 + translateX, 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 = Math.min(scaleX, scaleY); 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(); } groupedPhotosListView.setMoveProgress(-alpha); canvas.save(); canvas.translate(translateX, currentTranslationY / currentScale); canvas.translate((getContainerViewWidth() * (scale + 1) + AndroidUtilities.dp(30)) / 2, -currentTranslationY / currentScale); photoProgressViews[1].setScale(1.0f - scaleDiff); photoProgressViews[1].setAlpha(alpha); photoProgressViews[1].onDraw(canvas); canvas.restore(); } float translateX = currentTranslationX; float scaleDiff = 0; float alpha = 1; if (!zoomAnimation && translateX > maxX && currentEditMode == 0 && sendPhotoType != SELECT_TYPE_AVATAR) { alpha = Math.min(1.0f, (translateX - maxX) / getContainerViewWidth()); scaleDiff = alpha * 0.3f; alpha = 1.0f - alpha; translateX = maxX; } boolean drawTextureView = aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == View.VISIBLE; if (centerImage.hasBitmapImage() || drawTextureView && textureUploaded) { canvas.save(); canvas.translate(getContainerViewWidth() / 2 + getAdditionX(), getContainerViewHeight() / 2 + getAdditionY()); canvas.translate(translateX, currentTranslationY + currentPanTranslationY); canvas.scale(currentScale - scaleDiff, currentScale - scaleDiff); if (currentEditMode == 3 && keyboardSize > AndroidUtilities.dp(20)) { int trueH = getContainerViewHeight(true, 0); int h = getContainerViewHeight(false, 0); if (trueH != h) { canvas.translate(0, (trueH - h) / 2); } } int bitmapWidth; int bitmapHeight; if (drawTextureView && textureUploaded) { bitmapWidth = videoTextureView.getMeasuredWidth(); bitmapHeight = videoTextureView.getMeasuredHeight(); } else { bitmapWidth = centerImage.getBitmapWidth(); bitmapHeight = centerImage.getBitmapHeight(); } float scaleX = (float) getContainerViewWidth() / (float) bitmapWidth; float scaleY = (float) getContainerViewHeight() / (float) bitmapHeight; float scale = Math.min(scaleX, scaleY); 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 || paintingOverlay.getVisibility() == View.VISIBLE) { canvas.translate(-width / 2, -height / 2); canvas.scale(scale, scale); } if (drawTextureView) { if (!videoCrossfadeStarted && textureUploaded) { videoCrossfadeStarted = true; videoCrossfadeAlpha = 0.0f; videoCrossfadeAlphaLastTime = System.currentTimeMillis(); containerView.getMeasuredHeight(); } videoTextureView.setAlpha(alpha * videoCrossfadeAlpha); aspectRatioFrameLayout.draw(canvas); if (videoTextureView instanceof VideoEditTextureView) { ((VideoEditTextureView) videoTextureView).setViewRect((getContainerViewWidth() - width) / 2 + getAdditionX() + translateX, (getContainerViewHeight() - height) / 2 + getAdditionY() + currentTranslationY + currentPanTranslationY, width, height); } if (videoCrossfadeStarted && videoCrossfadeAlpha < 1.0f) { videoCrossfadeAlpha += dt / (playerInjected ? 100.0f : 200.0f); containerView.invalidate(); if (videoCrossfadeAlpha > 1.0f) { videoCrossfadeAlpha = 1.0f; } } paintingOverlay.setAlpha(alpha * videoCrossfadeAlpha); } if (paintingOverlay.getVisibility() == View.VISIBLE) { canvas.clipRect(0, 0, paintingOverlay.getMeasuredWidth(), paintingOverlay.getMeasuredHeight()); paintingOverlay.draw(canvas); } canvas.restore(); for (int a = 0; a < pressedDrawable.length; a++) { if (drawPressedDrawable[a] || pressedDrawableAlpha[a] != 0) { pressedDrawable[a].setAlpha((int) (pressedDrawableAlpha[a] * 255)); if (a == 0) { pressedDrawable[a].setBounds(0, 0, containerView.getMeasuredWidth() / 5, containerView.getMeasuredHeight()); } else { pressedDrawable[a].setBounds(containerView.getMeasuredWidth() - containerView.getMeasuredWidth() / 5, 0, containerView.getMeasuredWidth(), containerView.getMeasuredHeight()); } pressedDrawable[a].draw(canvas); } if (drawPressedDrawable[a]) { if (pressedDrawableAlpha[a] < 1.0f) { pressedDrawableAlpha[a] += dt / 180.0f; if (pressedDrawableAlpha[a] > 1.0f) { pressedDrawableAlpha[a] = 1.0f; } containerView.invalidate(); } } else { if (pressedDrawableAlpha[a] > 0.0f) { pressedDrawableAlpha[a] -= dt / 180.0f; if (pressedDrawableAlpha[a] < 0.0f) { pressedDrawableAlpha[a] = 0.0f; } containerView.invalidate(); } } } } boolean drawProgress; if (isCurrentVideo) { drawProgress = videoPlayer == null || !videoPlayer.isPlaying(); } else { drawProgress = true; } boolean drawMiniProgress = miniProgressView.getVisibility() == View.VISIBLE || miniProgressAnimator != null; if (drawProgress) { final float tx = !zoomAnimation && -translateX > maxX ? translateX + maxX : 0; float ty = currentScale == 1.0f ? currentTranslationY : 0; float progressAlpha = alpha; if (drawMiniProgress) { progressAlpha *= 1f - miniProgressView.getAlpha(); } if (pipAnimationInProgress) { progressAlpha *= actionBar.getAlpha(); } else if (photoProgressViews[0].backgroundState == PROGRESS_PAUSE) { ty += AndroidUtilities.dpf2(8) * (1f - actionBar.getAlpha()); } canvas.save(); canvas.translate(tx, ty); photoProgressViews[0].setScale(1.0f - scaleDiff); photoProgressViews[0].setAlpha(progressAlpha); photoProgressViews[0].onDraw(canvas); canvas.restore(); } if (drawMiniProgress && !pipAnimationInProgress) { canvas.save(); canvas.translate(miniProgressView.getLeft() + translateX, miniProgressView.getTop() + currentTranslationY / currentScale); miniProgressView.draw(canvas); canvas.restore(); } if (sideImage == leftImage) { if (sideImage.hasBitmapImage()) { canvas.save(); canvas.translate(getContainerViewWidth() / 2, getContainerViewHeight() / 2); canvas.translate(-(getContainerViewWidth() * (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 = Math.min(scaleX, scaleY); 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(); } groupedPhotosListView.setMoveProgress(1.0f - alpha); canvas.save(); canvas.translate(currentTranslationX, currentTranslationY / currentScale); canvas.translate(-(getContainerViewWidth() * (scale + 1) + AndroidUtilities.dp(30)) / 2, -currentTranslationY / currentScale); photoProgressViews[2].setScale(1.0f); photoProgressViews[2].setAlpha(1.0f); photoProgressViews[2].onDraw(canvas); canvas.restore(); } if (waitingForDraw != 0) { waitingForDraw--; if (waitingForDraw == 0) { if (textureImageView != null) { try { currentBitmap = Bitmaps.createBitmap(videoTextureView.getWidth(), videoTextureView.getHeight(), Bitmap.Config.ARGB_8888); changedTextureView.getBitmap(currentBitmap); } catch (Throwable e) { if (currentBitmap != null) { currentBitmap.recycle(); currentBitmap = null; } FileLog.e(e); } if (currentBitmap != null) { textureImageView.setVisibility(View.VISIBLE); textureImageView.setImageBitmap(currentBitmap); } else { textureImageView.setImageDrawable(null); } } pipVideoView.close(); pipVideoView = null; } else { containerView.invalidate(); } } if (padImageForHorizontalInsets) { canvas.restore(); } if (aspectRatioFrameLayout != null && videoForwardDrawable.isAnimating()) { int h = (int) (aspectRatioFrameLayout.getMeasuredHeight() * (scale - 1.0f)) / 2; videoForwardDrawable.setBounds(aspectRatioFrameLayout.getLeft(), aspectRatioFrameLayout.getTop() - h + (int) (currentTranslationY / currentScale), aspectRatioFrameLayout.getRight(), aspectRatioFrameLayout.getBottom() + h + (int) (currentTranslationY / currentScale)); videoForwardDrawable.draw(canvas); } } private void onActionClick(boolean download) { if (currentMessageObject == null && currentBotInlineResult == null || currentFileNames[0] == null) { return; } Uri uri = null; File file = null; isStreaming = false; 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; if (SharedConfig.streamMedia && (int) currentMessageObject.getDialogId() != 0 && currentMessageObject.isVideo() && currentMessageObject.canStreamVideo()) { try { int reference = FileLoader.getInstance(currentMessageObject.currentAccount).getFileReference(currentMessageObject); FileLoader.getInstance(currentAccount).loadFile(currentMessageObject.getDocument(), currentMessageObject, 1, 0); TLRPC.Document document = currentMessageObject.getDocument(); String params = "?account=" + currentMessageObject.currentAccount + "&id=" + document.id + "&hash=" + document.access_hash + "&dc=" + document.dc_id + "&size=" + document.size + "&mime=" + URLEncoder.encode(document.mime_type, "UTF-8") + "&rid=" + reference + "&name=" + URLEncoder.encode(FileLoader.getDocumentFileName(document), "UTF-8") + "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]); uri = Uri.parse("tg://" + currentMessageObject.getFileName() + params); isStreaming = true; checkProgress(0, false, false); } catch (Exception ignore) { } } } } } else if (currentBotInlineResult != null) { if (currentBotInlineResult.document != null) { file = FileLoader.getPathToAttach(currentBotInlineResult.document); if (!file.exists()) { file = null; } } else if (currentBotInlineResult.content instanceof TLRPC.TL_webDocument) { file = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(currentBotInlineResult.content.url) + "." + ImageLoader.getHttpUrlExtension(currentBotInlineResult.content.url, "mp4")); if (!file.exists()) { file = null; } } } if (file != null && uri == null) { uri = Uri.fromFile(file); } if (uri == null) { if (download) { if (currentMessageObject != null) { if (!FileLoader.getInstance(currentAccount).isLoadingFile(currentFileNames[0])) { FileLoader.getInstance(currentAccount).loadFile(currentMessageObject.getDocument(), currentMessageObject, 1, 0); } else { FileLoader.getInstance(currentAccount).cancelLoadFile(currentMessageObject.getDocument()); } } else if (currentBotInlineResult != null) { if (currentBotInlineResult.document != null) { if (!FileLoader.getInstance(currentAccount).isLoadingFile(currentFileNames[0])) { FileLoader.getInstance(currentAccount).loadFile(currentBotInlineResult.document, currentMessageObject, 1, 0); } else { FileLoader.getInstance(currentAccount).cancelLoadFile(currentBotInlineResult.document); } } else if (currentBotInlineResult.content instanceof TLRPC.TL_webDocument) { if (!ImageLoader.getInstance().isLoadingHttpFile(currentBotInlineResult.content.url)) { ImageLoader.getInstance().loadHttpFile(currentBotInlineResult.content.url, "mp4", currentAccount); } else { ImageLoader.getInstance().cancelLoadHttpFile(currentBotInlineResult.content.url); } } } Drawable drawable = centerImage.getStaticThumb(); if (drawable instanceof OtherDocumentPlaceholderDrawable) { ((OtherDocumentPlaceholderDrawable) drawable).checkFileExist(); } } } else { if (sharedMediaType == MediaDataController.MEDIA_FILE && !currentMessageObject.canPreviewDocument()) { AndroidUtilities.openDocument(currentMessageObject, parentActivity, null); return; } preparePlayer(uri, true, false); } } @Override public boolean onDown(MotionEvent e) { if (!doubleTap && checkImageView.getVisibility() != View.VISIBLE && !drawPressedDrawable[0] && !drawPressedDrawable[1]) { float x = e.getX(); int side = NekoConfig.disablePhotoSideAction ? 0 : Math.min(135, containerView.getMeasuredWidth() / 8); if (x < side) { if (leftImage.hasImageSet()) { drawPressedDrawable[0] = true; containerView.invalidate(); } } else if (x > containerView.getMeasuredWidth() - side) { if (rightImage.hasImageSet()) { drawPressedDrawable[1] = true; containerView.invalidate(); } } } return false; } @Override public boolean canDoubleTap(MotionEvent e) { if (checkImageView.getVisibility() != View.VISIBLE && !drawPressedDrawable[0] && !drawPressedDrawable[1]) { float x = e.getX(); int side = NekoConfig.disablePhotoSideAction ? 0 : Math.min(135, containerView.getMeasuredWidth() / 8); if (x < side || x > containerView.getMeasuredWidth() - side) { return currentMessageObject == null || currentMessageObject.isVideo() && (SystemClock.elapsedRealtime() - lastPhotoSetTime) >= 500 && canDoubleTapSeekVideo(e); } } return true; } private void hidePressedDrawables() { drawPressedDrawable[0] = drawPressedDrawable[1] = false; containerView.invalidate(); } @Override public void onUp(MotionEvent e) { hidePressedDrawables(); } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { if (!canZoom && !doubleTapEnabled) { return onSingleTapConfirmed(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; } float x = e.getX(); if (checkImageView.getVisibility() != View.VISIBLE) { int side = NekoConfig.disablePhotoSideAction ? 0 : Math.min(135, containerView.getMeasuredWidth() / 8); if (x < side) { if (leftImage.hasImageSet()) { switchToNextIndex(-1, true); return true; } } else if (x > containerView.getMeasuredWidth() - side) { if (rightImage.hasImageSet()) { switchToNextIndex(1, true); return true; } } } if (containerView.getTag() != null) { boolean drawTextureView = aspectRatioFrameLayout != null && aspectRatioFrameLayout.getVisibility() == View.VISIBLE; float y = e.getY(); if (sharedMediaType == MediaDataController.MEDIA_FILE && currentMessageObject != null) { if (!currentMessageObject.canPreviewDocument()) { float vy = (getContainerViewHeight() - AndroidUtilities.dp(360)) / 2.0f; if (y >= vy && y <= vy + AndroidUtilities.dp(360)) { onActionClick(true); return true; } } } else { if (photoProgressViews[0] != null && containerView != null) { int state = photoProgressViews[0].backgroundState; 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) { if (!drawTextureView) { if (state > PROGRESS_EMPTY && state <= PROGRESS_PLAY) { onActionClick(true); checkProgress(0, false, true); return true; } } else { if (state == PROGRESS_PLAY || state == PROGRESS_PAUSE) { if (photoProgressViews[0].isVisible()) { toggleVideoPlayer(); return true; } } } } } } toggleActionBar(!isActionBarVisible, true); } else if (sendPhotoType == 0 || sendPhotoType == 4) { if (isCurrentVideo) { if (videoPlayer != null && !muteVideo) { videoPlayer.setVolume(1.0f); } toggleVideoPlayer(); } else { checkImageView.performClick(); } } else if (currentBotInlineResult != null && (currentBotInlineResult.type.equals("video") || MessageObject.isVideoDocument(currentBotInlineResult.document))) { int state = photoProgressViews[0].backgroundState; if (state > 0 && state <= 3) { 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, false, true); return true; } } } else if (sendPhotoType == 2) { if (isCurrentVideo) { toggleVideoPlayer(); } } return true; } private boolean canDoubleTapSeekVideo(MotionEvent e) { if (videoPlayer == null) { return false; } int width = getContainerViewWidth(); float x = e.getX(); boolean forward = x >= width / 3 * 2; long current = videoPlayer.getCurrentPosition(); long total = videoPlayer.getDuration(); return current != C.TIME_UNSET && total > 15 * 1000 && (!forward || total - current > 10000); } @Override public boolean onDoubleTap(MotionEvent e) { if (videoPlayer != null && videoPlayerControlVisible) { long current = videoPlayer.getCurrentPosition(); long total = videoPlayer.getDuration(); float x = e.getX(); int width = getContainerViewWidth(); boolean forward = x >= width / 3 * 2; if (canDoubleTapSeekVideo(e)) { long old = current; if (x >= width / 3 * 2) { current += 10000; } else if (x < width / 3) { current -= 10000; } if (old != current) { if (current > total) { current = total; } else if (current < 0) { current = 0; } videoForwardDrawable.setLeftSide(x < width / 3); videoPlayer.seekTo(current); containerView.invalidate(); videoPlayerSeekbar.setProgress(current / (float) total); videoPlayerSeekbarView.invalidate(); return true; } } } 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; hidePressedDrawables(); return true; } @Override public boolean onDoubleTapEvent(MotionEvent e) { return false; } // video edit start private QualityChooseView qualityChooseView; private PickerBottomLayoutViewer qualityPicker; private RadialProgressView progressView; private VideoTimelinePlayView videoTimelineView; private AnimatorSet qualityChooseViewAnimation; private int selectedCompression; private int compressionsCount = -1; private int previousCompression; private int rotationValue; private int originalWidth; private int originalHeight; private int resultWidth; private int resultHeight; private int bitrate; private int originalBitrate; private float videoDuration; private int videoFramerate; private boolean videoConvertSupported; private long startTime; private long endTime; private float videoCutStart; private float videoCutEnd; private long audioFramesSize; private long videoFramesSize; private int estimatedSize; private long estimatedDuration; private long originalSize; private Runnable currentLoadingVideoRunnable; private MessageObject videoPreviewMessageObject; private boolean tryStartRequestPreviewOnFinish; private boolean loadInitialVideo; private boolean inPreview; private int previewViewEnd; private boolean requestingPreview; private String currentSubtitle; private class QualityChooseView extends View { private Paint paint; private TextPaint textPaint; private int circleSize; private int gapSize; private int sideSide; private int lineSize; private String lowQualityDescription; private String hightQualityDescription; private int startMovingQuality; public QualityChooseView(Context context) { super(context); paint = new Paint(Paint.ANTI_ALIAS_FLAG); textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); textPaint.setTextSize(AndroidUtilities.dp(14)); textPaint.setColor(0xffcdcdcd); lowQualityDescription = LocaleController.getString("AccDescrVideoCompressLow", R.string.AccDescrVideoCompressLow); hightQualityDescription = LocaleController.getString("AccDescrVideoCompressHigh", R.string.AccDescrVideoCompressHigh); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); if (event.getAction() == MotionEvent.ACTION_DOWN) { startMovingQuality = selectedCompression; getParent().requestDisallowInterceptTouchEvent(true); } if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { for (int a = 0; a < compressionsCount; a++) { int cx = sideSide + (lineSize + gapSize * 2 + circleSize) * a + circleSize / 2; int diff = lineSize / 2 + circleSize / 2 + gapSize; if (x > cx - diff && x < cx + diff) { if (selectedCompression != a) { selectedCompression = a; didChangedCompressionLevel(false); invalidate(); } break; } } } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { if (selectedCompression != startMovingQuality) { requestVideoPreview(1); } moving = false; } return true; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); circleSize = AndroidUtilities.dp(8); gapSize = AndroidUtilities.dp(2); sideSide = AndroidUtilities.dp(18); } @Override protected void onDraw(Canvas canvas) { if (compressionsCount != 1) { lineSize = (getMeasuredWidth() - circleSize * compressionsCount - gapSize * (compressionsCount * 2 - 2) - sideSide * 2) / (compressionsCount - 1); } else { lineSize = (getMeasuredWidth() - circleSize * compressionsCount - gapSize * 2 - sideSide * 2); } int cy = getMeasuredHeight() / 2 + AndroidUtilities.dp(6); for (int a = 0; a < compressionsCount; a++) { int cx = sideSide + (lineSize + gapSize * 2 + circleSize) * a + circleSize / 2; if (a <= selectedCompression) { paint.setColor(0xff53aeef); } else { paint.setColor(0x66ffffff); } canvas.drawCircle(cx, cy, a == selectedCompression ? AndroidUtilities.dp(6) : circleSize / 2, paint); if (a != 0) { int x = cx - circleSize / 2 - gapSize - lineSize; float startPadding = a == (selectedCompression + 1) ? AndroidUtilities.dpf2(2) : 0; float endPadding = a == selectedCompression ? AndroidUtilities.dpf2(2) : 0; canvas.drawRect(x + startPadding, cy - AndroidUtilities.dp(1), x + lineSize - endPadding, cy + AndroidUtilities.dp(2), paint); } } canvas.drawText(lowQualityDescription, sideSide, cy - AndroidUtilities.dp(16), textPaint); float width = textPaint.measureText(hightQualityDescription); canvas.drawText(hightQualityDescription, getMeasuredWidth() - sideSide - width, cy - AndroidUtilities.dp(16), textPaint); } } public void updateMuteButton() { if (videoPlayer != null) { videoPlayer.setMute(muteVideo); } if (!videoConvertSupported) { muteItem.setEnabled(false); muteItem.setClickable(false); muteItem.animate().alpha(0.5f).setDuration(180).start(); } else { muteItem.setEnabled(true); muteItem.setClickable(true); muteItem.animate().alpha(1f).setDuration(180).start(); if (muteVideo) { actionBar.setSubtitle(LocaleController.getString("SoundMuted", R.string.SoundMuted)); muteItem.setImageResource(R.drawable.video_send_mute); if (compressItem.getTag() != null) { compressItem.setAlpha(0.5f); compressItem.setEnabled(false); } //videoTimelineView.setMaxProgressDiff(30000.0f / videoDuration); muteItem.setContentDescription(LocaleController.getString("NoSound", R.string.NoSound)); } else { actionBar.setSubtitle(currentSubtitle); muteItem.setImageResource(R.drawable.video_send_unmute); muteItem.setContentDescription(LocaleController.getString("Sound", R.string.Sound)); if (compressItem.getTag() != null) { compressItem.setAlpha(1.0f); compressItem.setEnabled(true); } //videoTimelineView.setMaxProgressDiff(1.0f); } } } private void didChangedCompressionLevel(boolean request) { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); SharedPreferences.Editor editor = preferences.edit(); editor.putInt("compress_video2", selectedCompression); editor.apply(); updateWidthHeightBitrateForCompression(); updateVideoInfo(); if (request) { requestVideoPreview(1); } } private void updateVideoInfo() { if (actionBar == null) { return; } if (compressionsCount == 0) { actionBar.setSubtitle(null); return; } int compressIconWidth = 64; if (selectedCompression < 2) { compressItem.setImageResource(R.drawable.video_quality1); compressIconWidth = 48; } else if (selectedCompression == 2) { compressItem.setImageResource(R.drawable.video_quality2); compressIconWidth = 64; } else if (selectedCompression == 3) { compressItem.setImageResource(R.drawable.video_quality3); compressIconWidth = 64; } compressItem.setPadding(AndroidUtilities.dp(70 - compressIconWidth) / 2, 0, AndroidUtilities.dp(70 - compressIconWidth) / 2, 0); compressItem.requestLayout(); String[] compressionStrings = {"360", "480", "720", "1080"}; compressItem.setContentDescription(LocaleController.getString("AccDescrVideoQuality", R.string.AccDescrVideoQuality) + ", " + compressionStrings[Math.max(0, selectedCompression)]); estimatedDuration = (long) Math.ceil((videoTimelineView.getRightProgress() - videoTimelineView.getLeftProgress()) * videoDuration); int width; int height; if (compressItem.getTag() == null) { width = rotationValue == 90 || rotationValue == 270 ? originalHeight : originalWidth; height = rotationValue == 90 || rotationValue == 270 ? originalWidth : originalHeight; estimatedSize = (int) (originalSize * ((float) estimatedDuration / videoDuration)); } else { width = rotationValue == 90 || rotationValue == 270 ? resultHeight : resultWidth; height = rotationValue == 90 || rotationValue == 270 ? resultWidth : resultHeight; estimatedSize = (int) ((audioFramesSize + videoFramesSize) * ((float) estimatedDuration / videoDuration)); estimatedSize += estimatedSize / (32 * 1024) * 16; } videoCutStart = videoTimelineView.getLeftProgress(); videoCutEnd = videoTimelineView.getRightProgress(); if (videoCutStart == 0) { startTime = -1; } else { startTime = (long) (videoCutStart * videoDuration) * 1000; } if (videoCutEnd == 1) { endTime = -1; } else { endTime = (long) (videoCutEnd * videoDuration) * 1000; } String videoDimension = String.format("%dx%d", width, height); String videoTimeSize = String.format("%s, ~%s", AndroidUtilities.formatShortDuration((int) (estimatedDuration / 1000)), AndroidUtilities.formatFileSize(estimatedSize)); currentSubtitle = String.format("%s, %s", videoDimension, videoTimeSize); actionBar.setSubtitle(muteVideo ? LocaleController.getString("SoundMuted", R.string.SoundMuted) : currentSubtitle); } private void requestVideoPreview(int request) { if (videoPreviewMessageObject != null) { MediaController.getInstance().cancelVideoConvert(videoPreviewMessageObject); } boolean wasRequestingPreview = requestingPreview && !tryStartRequestPreviewOnFinish; requestingPreview = false; loadInitialVideo = false; progressView.setVisibility(View.INVISIBLE); if (request == 1) { if (resultHeight == originalHeight && resultWidth == originalWidth) { tryStartRequestPreviewOnFinish = false; photoProgressViews[0].setProgress(0, photoProgressViews[0].backgroundState == 0 || photoProgressViews[0].previousBackgroundState == 0); photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false); if (!wasRequestingPreview) { preparePlayer(currentPlayingVideoFile, false, false, currentSavedFilterState); videoPlayer.seekTo((long) (videoTimelineView.getLeftProgress() * videoDuration)); } else { loadInitialVideo = true; } } else { releasePlayer(false); if (videoPreviewMessageObject == null) { TLRPC.TL_message message = new TLRPC.TL_message(); message.id = 0; message.message = ""; message.media = new TLRPC.TL_messageMediaEmpty(); message.action = new TLRPC.TL_messageActionEmpty(); message.dialog_id = currentDialogId; videoPreviewMessageObject = new MessageObject(UserConfig.selectedAccount, message, false); videoPreviewMessageObject.messageOwner.attachPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), "video_preview.mp4").getAbsolutePath(); videoPreviewMessageObject.videoEditedInfo = new VideoEditedInfo(); videoPreviewMessageObject.videoEditedInfo.rotationValue = rotationValue; videoPreviewMessageObject.videoEditedInfo.originalWidth = originalWidth; videoPreviewMessageObject.videoEditedInfo.originalHeight = originalHeight; videoPreviewMessageObject.videoEditedInfo.framerate = videoFramerate; videoPreviewMessageObject.videoEditedInfo.originalPath = currentPlayingVideoFile.getPath(); } long start = videoPreviewMessageObject.videoEditedInfo.startTime = startTime; long end = videoPreviewMessageObject.videoEditedInfo.endTime = endTime; if (start == -1) { start = 0; } if (end == -1) { end = (long) (videoDuration * 1000); } if (end - start > 5000000) { videoPreviewMessageObject.videoEditedInfo.endTime = start + 5000000; } videoPreviewMessageObject.videoEditedInfo.bitrate = bitrate; videoPreviewMessageObject.videoEditedInfo.resultWidth = resultWidth; videoPreviewMessageObject.videoEditedInfo.resultHeight = resultHeight; videoPreviewMessageObject.videoEditedInfo.needUpdateProgress = true; videoPreviewMessageObject.videoEditedInfo.originalDuration = (long) (videoDuration * 1000); if (!MediaController.getInstance().scheduleVideoConvert(videoPreviewMessageObject, true)) { tryStartRequestPreviewOnFinish = true; } requestingPreview = true; photoProgressViews[0].setProgress(0, photoProgressViews[0].backgroundState == 0 || photoProgressViews[0].previousBackgroundState == 0); photoProgressViews[0].setBackgroundState(PROGRESS_EMPTY, false); } } else { tryStartRequestPreviewOnFinish = false; photoProgressViews[0].setBackgroundState(PROGRESS_PLAY, false); if (request == 2) { preparePlayer(currentPlayingVideoFile, false, false, currentSavedFilterState); videoPlayer.seekTo((long) (videoTimelineView.getLeftProgress() * videoDuration)); } } containerView.invalidate(); } private void updateWidthHeightBitrateForCompression() { if (compressionsCount <= 0) { return; } if (selectedCompression >= compressionsCount) { selectedCompression = compressionsCount - 1; } float maxSize; switch (selectedCompression) { case 0: maxSize = 480.0f; break; case 1: maxSize = 854.0f; break; case 2: maxSize = 1280.0f; break; case 3: default: maxSize = 1920.0f; break; } float scale = originalWidth > originalHeight ? maxSize / originalWidth : maxSize / originalHeight; if (selectedCompression == compressionsCount - 1 && scale >= 1f) { resultWidth = originalWidth; resultHeight = originalHeight; } else { resultWidth = Math.round(originalWidth * scale / 2) * 2; resultHeight = Math.round(originalHeight * scale / 2) * 2; } if (bitrate != 0) { if (resultWidth == originalWidth && resultHeight == originalHeight) { bitrate = originalBitrate; } else { bitrate = MediaController.makeVideoBitrate(originalHeight, originalWidth, originalBitrate, resultHeight, resultWidth); } videoFramesSize = (long) (bitrate / 8 * videoDuration / 1000); } } private void showQualityView(final boolean show) { if (show) { previousCompression = selectedCompression; } if (qualityChooseViewAnimation != null) { qualityChooseViewAnimation.cancel(); } qualityChooseViewAnimation = new AnimatorSet(); if (show) { qualityChooseView.setTag(1); qualityChooseViewAnimation.playTogether( ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, 0, AndroidUtilities.dp(152)), ObjectAnimator.ofFloat(pickerViewSendButton, View.TRANSLATION_Y, 0, AndroidUtilities.dp(152)), ObjectAnimator.ofFloat(bottomLayout, View.TRANSLATION_Y, -AndroidUtilities.dp(48), AndroidUtilities.dp(104)) ); } else { qualityChooseView.setTag(null); qualityChooseViewAnimation.playTogether( ObjectAnimator.ofFloat(qualityChooseView, View.TRANSLATION_Y, 0, AndroidUtilities.dp(166)), ObjectAnimator.ofFloat(qualityPicker, View.TRANSLATION_Y, 0, AndroidUtilities.dp(166)), ObjectAnimator.ofFloat(bottomLayout, View.TRANSLATION_Y, -AndroidUtilities.dp(48), AndroidUtilities.dp(118)) ); } qualityChooseViewAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (!animation.equals(qualityChooseViewAnimation)) { return; } qualityChooseViewAnimation = new AnimatorSet(); if (show) { qualityChooseView.setVisibility(View.VISIBLE); qualityPicker.setVisibility(View.VISIBLE); qualityChooseViewAnimation.playTogether( ObjectAnimator.ofFloat(qualityChooseView, View.TRANSLATION_Y, 0), ObjectAnimator.ofFloat(qualityPicker, View.TRANSLATION_Y, 0), ObjectAnimator.ofFloat(bottomLayout, View.TRANSLATION_Y, -AndroidUtilities.dp(48)) ); } else { qualityChooseView.setVisibility(View.INVISIBLE); qualityPicker.setVisibility(View.INVISIBLE); qualityChooseViewAnimation.playTogether( ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, 0), ObjectAnimator.ofFloat(pickerViewSendButton, View.TRANSLATION_Y, 0), ObjectAnimator.ofFloat(bottomLayout, View.TRANSLATION_Y, -AndroidUtilities.dp(48)) ); } qualityChooseViewAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (animation.equals(qualityChooseViewAnimation)) { qualityChooseViewAnimation = null; } } }); qualityChooseViewAnimation.setDuration(200); qualityChooseViewAnimation.setInterpolator(AndroidUtilities.decelerateInterpolator); qualityChooseViewAnimation.start(); } @Override public void onAnimationCancel(Animator animation) { qualityChooseViewAnimation = null; } }); qualityChooseViewAnimation.setDuration(200); qualityChooseViewAnimation.setInterpolator(AndroidUtilities.accelerateInterpolator); qualityChooseViewAnimation.start(); if (cameraItem.getVisibility() == View.VISIBLE) { cameraItem.animate().scaleX(show ? 0.25f : 1f) .scaleY(show ? 0.25f : 1f) .alpha(show ? 0 : 1) .setDuration(200); } if (muteItem.getVisibility() == View.VISIBLE) { muteItem.animate().scaleX(show ? 0.25f : 1f) .scaleY(show ? 0.25f : 1f) .alpha(show ? 0 : 1) .setDuration(200); } } private ByteArrayInputStream cleanBuffer(byte[] data) { byte[] output = new byte[data.length]; int inPos = 0; int outPos = 0; while (inPos < data.length) { if (data[inPos] == 0 && data[inPos + 1] == 0 && data[inPos + 2] == 3) { output[outPos] = 0; output[outPos + 1] = 0; inPos += 3; outPos += 2; } else { output[outPos] = data[inPos]; inPos++; outPos++; } } return new ByteArrayInputStream(output, 0, outPos); } private void processOpenVideo(final String videoPath, boolean muted, float start, float end) { if (currentLoadingVideoRunnable != null) { Utilities.globalQueue.cancelRunnable(currentLoadingVideoRunnable); currentLoadingVideoRunnable = null; } videoTimelineView.setVideoPath(videoPath, start, end); videoPreviewMessageObject = null; muteVideo = muted; compressionsCount = -1; rotationValue = 0; videoFramerate = 25; File file = new File(videoPath); originalSize = file.length(); Utilities.globalQueue.postRunnable(currentLoadingVideoRunnable = new Runnable() { @Override public void run() { if (currentLoadingVideoRunnable != this) { return; } int videoBitrate = MediaController.getVideoBitrate(videoPath); int[] params = new int[AnimatedFileDrawable.PARAM_NUM_COUNT]; AnimatedFileDrawable.getVideoInfo(videoPath, params); if (currentLoadingVideoRunnable != this) { return; } currentLoadingVideoRunnable = null; AndroidUtilities.runOnUIThread(() -> { if (parentActivity == null) { return; } boolean hasAudio = params[AnimatedFileDrawable.PARAM_NUM_HAS_AUDIO] != 0; videoConvertSupported = params[AnimatedFileDrawable.PARAM_NUM_SUPPORTED_VIDEO_CODEC] != 0 && (!hasAudio || params[AnimatedFileDrawable.PARAM_NUM_SUPPORTED_AUDIO_CODEC] != 0); audioFramesSize = params[AnimatedFileDrawable.PARAM_NUM_AUDIO_FRAME_SIZE]; videoDuration = params[AnimatedFileDrawable.PARAM_NUM_DURATION]; originalBitrate = bitrate = videoBitrate; videoFramerate = params[AnimatedFileDrawable.PARAM_NUM_FRAMERATE]; videoFramesSize = (long) (bitrate / 8 * videoDuration / 1000); if (videoConvertSupported) { rotationValue = params[AnimatedFileDrawable.PARAM_NUM_ROTATION]; resultWidth = originalWidth = params[AnimatedFileDrawable.PARAM_NUM_WIDTH]; resultHeight = originalHeight = params[AnimatedFileDrawable.PARAM_NUM_HEIGHT]; updateCompressionsCount(originalWidth, originalHeight); SharedPreferences preferences = MessagesController.getGlobalMainSettings(); selectedCompression = preferences.getInt("compress_video2", selectCompression()); updateWidthHeightBitrateForCompression(); if (selectedCompression > compressionsCount - 1) { selectedCompression = compressionsCount - 1; } setCompressItemEnabled(compressionsCount > 1, true); if (BuildVars.LOGS_ENABLED) { FileLog.d("compressionsCount = " + compressionsCount + " w = " + originalWidth + " h = " + originalHeight); } if (Build.VERSION.SDK_INT < 18 && compressItem.getTag() != null) { try { MediaCodecInfo codecInfo = MediaController.selectCodec(MediaController.VIDEO_MIME_TYPE); if (codecInfo == null) { if (BuildVars.LOGS_ENABLED) { FileLog.d("no codec info for " + MediaController.VIDEO_MIME_TYPE); } videoConvertSupported = false; setCompressItemEnabled(false, true); } else { String name = codecInfo.getName(); if (name.equals("OMX.google.h264.encoder") || name.equals("OMX.ST.VFM.H264Enc") || name.equals("OMX.Exynos.avc.enc") || name.equals("OMX.MARVELL.VIDEO.HW.CODA7542ENCODER") || name.equals("OMX.MARVELL.VIDEO.H264ENCODER") || name.equals("OMX.k3.video.encoder.avc") || name.equals("OMX.TI.DUCATI1.VIDEO.H264E")) { if (BuildVars.LOGS_ENABLED) { FileLog.d("unsupported encoder = " + name); } videoConvertSupported = false; setCompressItemEnabled(false, true); } else { if (MediaController.selectColorFormat(codecInfo, MediaController.VIDEO_MIME_TYPE) == 0) { if (BuildVars.LOGS_ENABLED) { FileLog.d("no color format for " + MediaController.VIDEO_MIME_TYPE); } setCompressItemEnabled(false, true); } } } } catch (Exception e) { setCompressItemEnabled(false, true); FileLog.e(e); } } qualityChooseView.invalidate(); } else { setCompressItemEnabled(false, true); compressionsCount = 0; } updateVideoInfo(); updateMuteButton(); }); } }); } private int selectCompression() { return Math.round(DownloadController.getInstance(currentAccount).getMaxVideoBitrate() / (100f / compressionsCount)) - 1; } private void updateCompressionsCount(int h, int w) { int maxSize = Math.max(h, w); if (maxSize > 1280) { compressionsCount = 4; } else if (maxSize > 854) { compressionsCount = 3; } else if (maxSize > 640) { compressionsCount = 2; } else { compressionsCount = 1; } } private void setCompressItemEnabled(boolean enabled, boolean animated) { if (compressItem == null) { return; } if (enabled && compressItem.getTag() != null || !enabled && compressItem.getTag() == null) { return; } compressItem.setTag(enabled ? 1 : null); if (compressItemAnimation != null) { compressItemAnimation.cancel(); compressItemAnimation = null; } if (animated) { compressItemAnimation = new AnimatorSet(); compressItemAnimation.playTogether( ObjectAnimator.ofFloat(compressItem, View.ALPHA, enabled ? 1.0f : 0.5f), ObjectAnimator.ofFloat(paintItem, View.ALPHA, videoConvertSupported ? 1.0f : 0.5f), ObjectAnimator.ofFloat(tuneItem, View.ALPHA, videoConvertSupported ? 1.0f : 0.5f)); compressItemAnimation.setDuration(180); compressItemAnimation.setInterpolator(decelerateInterpolator); compressItemAnimation.start(); } else { compressItem.setAlpha(enabled ? 1.0f : 0.5f); } } private void updateAccessibilityOverlayVisibility() { if (playButtonAccessibilityOverlay != null) { final int state = photoProgressViews[0].backgroundState; if (photoProgressViews[0].isVisible() && (state == PROGRESS_PLAY || state == PROGRESS_PAUSE)) { if (state == PROGRESS_PLAY) { playButtonAccessibilityOverlay.setContentDescription(LocaleController.getString("AccActionPlay", R.string.AccActionPlay)); } else { playButtonAccessibilityOverlay.setContentDescription(LocaleController.getString("AccActionPause", R.string.AccActionPause)); } playButtonAccessibilityOverlay.setVisibility(View.VISIBLE); } else { playButtonAccessibilityOverlay.setVisibility(View.INVISIBLE); } } } private class ListAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; public ListAdapter(Context context) { mContext = context; } @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { return false; } @Override public int getItemCount() { if (placeProvider != null && placeProvider.getSelectedPhotosOrder() != null) { return placeProvider.getSelectedPhotosOrder().size(); } return 0; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { PhotoPickerPhotoCell cell = new PhotoPickerPhotoCell(mContext); cell.checkFrame.setOnClickListener(v -> { Object photoEntry = ((View) v.getParent()).getTag(); int idx = imagesArrLocals.indexOf(photoEntry); if (idx >= 0) { int num = placeProvider.setPhotoChecked(idx, getCurrentVideoEditedInfo()); boolean checked = placeProvider.isPhotoChecked(idx); if (idx == currentIndex) { checkImageView.setChecked(-1, false, true); } if (num >= 0) { selectedPhotosAdapter.notifyItemRemoved(num); if (num == 0) { selectedPhotosAdapter.notifyItemChanged(0); } } updateSelectedCount(); } else { int num = placeProvider.setPhotoUnchecked(photoEntry); if (num >= 0) { selectedPhotosAdapter.notifyItemRemoved(num); if (num == 0) { selectedPhotosAdapter.notifyItemChanged(0); } updateSelectedCount(); } } }); return new RecyclerListView.Holder(cell); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { PhotoPickerPhotoCell cell = (PhotoPickerPhotoCell) holder.itemView; cell.setItemWidth(AndroidUtilities.dp(85), position != 0 ? AndroidUtilities.dp(6) : 0); BackupImageView imageView = cell.imageView; boolean showing; imageView.setOrientation(0, true); ArrayList order = placeProvider.getSelectedPhotosOrder(); Object object = placeProvider.getSelectedPhotos().get(order.get(position)); if (object instanceof MediaController.PhotoEntry) { MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; cell.setTag(photoEntry); cell.videoInfoContainer.setVisibility(View.INVISIBLE); if (photoEntry.thumbPath != null) { imageView.setImage(photoEntry.thumbPath, null, mContext.getResources().getDrawable(R.drawable.nophotos)); } else if (photoEntry.path != null) { imageView.setOrientation(photoEntry.orientation, true); if (photoEntry.isVideo) { cell.videoInfoContainer.setVisibility(View.VISIBLE); cell.videoTextView.setText(AndroidUtilities.formatShortDuration(photoEntry.duration)); imageView.setImage("vthumb://" + photoEntry.imageId + ":" + photoEntry.path, null, mContext.getResources().getDrawable(R.drawable.nophotos)); } else { imageView.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, mContext.getResources().getDrawable(R.drawable.nophotos)); } } else { imageView.setImageResource(R.drawable.nophotos); } cell.setChecked(-1, true, false); cell.checkBox.setVisibility(View.VISIBLE); } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage photoEntry = (MediaController.SearchImage) object; cell.setTag(photoEntry); cell.setImage(photoEntry); cell.videoInfoContainer.setVisibility(View.INVISIBLE); cell.setChecked(-1, true, false); cell.checkBox.setVisibility(View.VISIBLE); } } @Override public int getItemViewType(int i) { return 0; } } }