From c71626f80e5980713e08c61044bc61d77cdc21d0 Mon Sep 17 00:00:00 2001 From: luvletter2333 Date: Sat, 21 Jan 2023 20:56:50 +0800 Subject: [PATCH] fix: use latest photo editor --- .../Paint/Views/LPhotoPaintView.java | 3249 +++++++++++++++++ .../java/org/telegram/ui/PhotoViewer.java | 7 +- 2 files changed, 3253 insertions(+), 3 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java new file mode 100644 index 000000000..d98141e30 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java @@ -0,0 +1,3249 @@ +package org.telegram.ui.Components.Paint.Views; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.SweepGradient; +import android.graphics.drawable.GradientDrawable; +import android.os.Build; +import android.os.Looper; +import android.text.Layout; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.core.graphics.ColorUtils; +import androidx.dynamicanimation.animation.FloatValueHolder; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Bitmaps; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.DispatchQueue; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.VideoEditedInfo; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.BubbleActivity; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.ChatActivityEnterViewAnimatedIconView; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.EmojiView; +import org.telegram.ui.Components.IPhotoPaintView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Paint.Brush; +import org.telegram.ui.Components.Paint.ColorPickerBottomSheet; +import org.telegram.ui.Components.Paint.PaintTypeface; +import org.telegram.ui.Components.Paint.Painting; +import org.telegram.ui.Components.Paint.PersistColorPalette; +import org.telegram.ui.Components.Paint.RenderView; +import org.telegram.ui.Components.Paint.Swatch; +import org.telegram.ui.Components.Paint.UndoStore; +import org.telegram.ui.Components.Point; +import org.telegram.ui.Components.RLottieDrawable; +import org.telegram.ui.Components.Size; +import org.telegram.ui.Components.SizeNotifierFrameLayoutPhoto; +import org.telegram.ui.Components.StickerMasksAlert; +import org.telegram.ui.PhotoViewer; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPaintView, PaintToolsView.Delegate, EntityView.EntityViewDelegate, PaintTextOptionsView.Delegate, SizeNotifierFrameLayoutPhoto.SizeNotifierFrameLayoutPhotoDelegate { + private PaintCancelView cancelButton; + private PaintDoneView doneButton; + private float offsetTranslationY; + + private Bitmap bitmapToEdit; + private Bitmap facesBitmap; + private UndoStore undoStore; + + private DispatchQueue queue; + + private MediaController.CropState currentCropState; + private float panTranslationProgress; + private float panTranslationY, scale, inputTransformX, inputTransformY, transformX, transformY, imageWidth, imageHeight; + private boolean ignoreLayout; + private float baseScale; + private Size paintingSize; + + private EntityView currentEntityView; + private boolean editingText; + private int selectedTextType; + + private boolean inBubbleMode; + + private RenderView renderView; + private View renderInputView; + private FrameLayout selectionContainerView; + private EntitiesContainerView entitiesView; + private FrameLayout topLayout; + private FrameLayout bottomLayout; + private FrameLayout overlayLayout; + private FrameLayout pipetteContainerLayout; + private LinearLayout tabsLayout; + + private int tabsSelectedIndex = 0; + private int tabsNewSelectedIndex = -1; + private float tabsSelectionProgress; + private ValueAnimator tabsSelectionAnimator; + + private boolean ignoreToolChangeAnimationOnce; + + private PaintWeightChooserView weightChooserView; + private PaintWeightChooserView.ValueOverride weightDefaultValueOverride = new PaintWeightChooserView.ValueOverride() { + @Override + public float get() { + Brush brush = renderView.getCurrentBrush(); + if (brush == null) { + return PersistColorPalette.getInstance(currentAccount).getCurrentWeight(); + } + return PersistColorPalette.getInstance(currentAccount).getWeight(String.valueOf(Brush.BRUSHES_LIST.indexOf(brush)), brush.getDefaultWeight()); + } + + @Override + public void set(float val) { + PersistColorPalette.getInstance(currentAccount).setWeight(String.valueOf(Brush.BRUSHES_LIST.indexOf(renderView.getCurrentBrush())), val); + colorSwatch.brushWeight = val; + setCurrentSwatch(colorSwatch, true); + } + }; + +// private ArrayList faces; + private int originalBitmapRotation; + private BigInteger lcm; + + private TextView drawTab; + private TextView stickerTab; + private TextView textTab; + + private PaintToolsView paintToolsView; + private PaintTextOptionsView textOptionsView; + private PaintTypefaceListView typefaceListView; + private ImageView undoButton; + private LinearLayout zoomOutButton; + private ImageView zoomOutImage; + private TextView zoomOutText; + private TextView undoAllButton; + private TextView cancelTextButton; + private TextView doneTextButton; + + private Paint typefaceMenuOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint typefaceMenuBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private float typefaceMenuTransformProgress; + private boolean isTypefaceMenuShown; + private SpringAnimation typefaceMenuTransformAnimation; + + private PaintColorsListView colorsListView; + private Paint colorPickerRainbowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint colorSwatchPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint colorSwatchOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Swatch colorSwatch = new Swatch(Color.WHITE, 1f, 0.016773745f); + private boolean fillShapes = false; + + private boolean isColorListShown; + private SpringAnimation toolsTransformAnimation; + private float toolsTransformProgress; + private Paint toolsPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private int currentAccount; + private Theme.ResourcesProvider resourcesProvider; + + private ActionBarPopupWindow popupWindow; + private ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout; + private Rect popupRect; + + private Runnable onDoneButtonClickedListener; + + @SuppressLint("NotifyDataSetChanged") + public LPhotoPaintView(Context context, int currentAccount, Bitmap bitmap, Bitmap originalBitmap, int originalRotation, ArrayList entities, MediaController.CropState cropState, Runnable onInit, Theme.ResourcesProvider resourcesProvider) { + super(context, true); + setDelegate(this); + + this.currentAccount = currentAccount; + this.resourcesProvider = key -> { + switch (key) { + case Theme.key_actionBarDefaultSubmenuBackground: return 0xFF282829; + case Theme.key_actionBarDefaultSubmenuItem: return 0xFFFFFFFF; + + case Theme.key_dialogBackground: return -14803426; + case Theme.key_dialogTextBlack: return -592138; + case Theme.key_dialogTextGray3: return -8553091; + + case Theme.key_chat_emojiPanelBackground: return 0xFF000000; + case Theme.key_chat_emojiPanelShadowLine: return -1610612736; + case Theme.key_chat_emojiBottomPanelIcon: return -9539985; + case Theme.key_chat_emojiPanelBackspace: return -9539985; + case Theme.key_chat_emojiPanelIcon: return -9539985; + case Theme.key_chat_emojiPanelIconSelected: return -10177041; + case Theme.key_windowBackgroundWhiteBlackText: return -1; + case Theme.key_featuredStickers_addedIcon: return -11754001; + case Theme.key_listSelector: return 0x1FFFFFFF; + + case Theme.key_profile_tabSelectedText: return 0xFFFFFFFF; + case Theme.key_profile_tabText: return 0xFFFFFFFF; + case Theme.key_profile_tabSelectedLine: return 0xFFFFFFFF; + case Theme.key_profile_tabSelector: return 0x14FFFFFF; + + default: { + if (resourcesProvider != null) { + return resourcesProvider.getColor(key); + } else { + return Theme.getColor(key); + } + } + } + }; + this.currentCropState = cropState; + + inBubbleMode = context instanceof BubbleActivity; + + PersistColorPalette palette = PersistColorPalette.getInstance(currentAccount); + colorSwatch.color = palette.getColor(0); + colorSwatch.brushWeight = palette.getCurrentWeight(); + + queue = new DispatchQueue("Paint"); + + bitmapToEdit = bitmap; + // NekoX: Ignore face detection related +// facesBitmap = originalBitmap; + originalBitmapRotation = originalRotation; + undoStore = new UndoStore(); + undoStore.setDelegate(() -> { + boolean canUndo = undoStore.canUndo(); + undoButton.animate().cancel(); + undoButton.animate().alpha(canUndo ? 1f : 0.6f).translationY(0).setDuration(150).start(); + undoButton.setClickable(canUndo); + undoAllButton.animate().cancel(); + undoAllButton.animate().alpha(canUndo ? 1f : 0.6f).translationY(0).setDuration(150).start(); + undoAllButton.setClickable(canUndo); + }); + + renderView = new RenderView(context, new Painting(getPaintingSize(), originalBitmap, originalRotation), bitmapToEdit) { + @Override + public void selectBrush(Brush brush) { + int index = 1 + Brush.BRUSHES_LIST.indexOf(brush); + if (index > 1 && originalBitmap == null) { + index--; + } + paintToolsView.select(index); + onBrushSelected(brush); + } + }; + renderView.setDelegate(new RenderView.RenderViewDelegate() { + + @Override + public void onFirstDraw() { + onInit.run(); + } + + @Override + public void onBeganDrawing() { + if (currentEntityView != null) { + selectEntity(null); + } + weightChooserView.setViewHidden(true); + } + + @Override + public void onFinishedDrawing(boolean moved) { + undoStore.getDelegate().historyChanged(); + weightChooserView.setViewHidden(false); + } + + @Override + public boolean shouldDraw() { + boolean draw = currentEntityView == null; + if (!draw) { + selectEntity(null); + } + return draw; + } + + @Override + public void invalidateInputView() { + if (renderInputView != null) { + renderInputView.invalidate(); + } + } + + @Override + public void resetBrush() { + if (ignoreToolChangeAnimationOnce) { + ignoreToolChangeAnimationOnce = false; + return; + } + paintToolsView.select(1); + onBrushSelected(Brush.BRUSHES_LIST.get(0)); + } + }); + renderView.setUndoStore(undoStore); + renderView.setQueue(queue); + renderView.setVisibility(View.INVISIBLE); + addView(renderView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + + renderInputView = new View(context) { + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (renderView != null) { + renderView.onDrawForInput(canvas); + } + } + }; + renderInputView.setVisibility(View.INVISIBLE); + addView(renderInputView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + + entitiesView = new EntitiesContainerView(context, new EntitiesContainerView.EntitiesContainerViewDelegate() { + @Override + public boolean shouldReceiveTouches() { + return true; + } + + @Override + public EntityView onSelectedEntityRequest() { + return currentEntityView; + } + + @Override + public void onEntityDeselect() { + selectEntity(null); + } + }) { + Paint linePaint = new Paint(); + + long lastUpdate; + float stickyXAlpha, stickyYAlpha; + + { + setWillNotDraw(false); + linePaint.setStrokeWidth(AndroidUtilities.dp(2)); + linePaint.setStyle(Paint.Style.STROKE); + linePaint.setColor(Color.WHITE); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + long dt = Math.min(16, System.currentTimeMillis() - lastUpdate); + lastUpdate = System.currentTimeMillis(); + boolean drawStickyX = false, drawStickyY = false; + + if (currentEntityView != null && currentEntityView.hasTouchDown() && currentEntityView.hasPanned()) { + drawStickyX = currentEntityView.hasStickyX(); + drawStickyY = currentEntityView.hasStickyY(); + } + + if (drawStickyX && stickyXAlpha != 1f) { + stickyXAlpha = Math.min(1f, stickyXAlpha + dt / 150f); + invalidate(); + } else if (!drawStickyX && stickyXAlpha != 0f) { + stickyXAlpha = Math.max(0f, stickyXAlpha - dt / 150f); + invalidate(); + } + + if (drawStickyY && stickyYAlpha != 1f) { + stickyYAlpha = Math.min(1f, stickyYAlpha + dt / 150f); + invalidate(); + } else if (!drawStickyY && stickyYAlpha != 0f) { + stickyYAlpha = Math.max(0f, stickyYAlpha - dt / 150f); + invalidate(); + } + + if (stickyYAlpha != 0f) { + linePaint.setAlpha((int) (stickyYAlpha * 0xFF)); + float y = getMeasuredHeight() / 2f; + canvas.drawLine(0, y, getMeasuredWidth(), y, linePaint); + } + if (stickyXAlpha != 0f) { + linePaint.setAlpha((int) (stickyXAlpha * 0xFF)); + float x = getMeasuredWidth() / 2f; + canvas.drawLine(x, 0, x, getMeasuredHeight(), linePaint); + } + } + }; + addView(entitiesView); + + if (entities != null && !entities.isEmpty()) { + for (int a = 0, N = entities.size(); a < N; a++) { + VideoEditedInfo.MediaEntity entity = entities.get(a); + EntityView view; + if (entity.type == 0) { + StickerView stickerView = createSticker(entity.parentObject, entity.document, false); + if ((entity.subType & 2) != 0) { + stickerView.mirror(); + } + view = stickerView; + ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); + layoutParams.width = entity.viewWidth; + layoutParams.height = entity.viewHeight; + } else if (entity.type == 1) { + TextPaintView textPaintView = createText(false); + int type; + if ((entity.subType & 1) != 0) { + type = 0; + } else if ((entity.subType & 4) != 0) { + type = 2; + } else { + type = 1; + } + textPaintView.setType(type); + textPaintView.setTypeface(entity.textTypeface); + textPaintView.setBaseFontSize(entity.fontSize); + SpannableString text = new SpannableString(entity.text); + for (VideoEditedInfo.EmojiEntity e : entity.entities) { + text.setSpan(new AnimatedEmojiSpan(e.document_id, textPaintView.getFontMetricsInt()), e.offset, e.offset + e.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + CharSequence charSequence = text; + charSequence = Emoji.replaceEmoji(charSequence, textPaintView.getFontMetricsInt(), (int) (textPaintView.getFontSize() * .8f), false); + textPaintView.setText(charSequence); + setTextAlignment(textPaintView, entity.textAlign); + Swatch swatch = textPaintView.getSwatch(); + swatch.color = entity.color; + textPaintView.setSwatch(swatch); + view = textPaintView; + } else { + continue; + } + view.setX(entity.x * paintingSize.width - entity.viewWidth * (1 - entity.scale) / 2); + view.setY(entity.y * paintingSize.height - entity.viewHeight * (1 - entity.scale) / 2); + view.setPosition(new Point(view.getX() + entity.viewWidth / 2f, view.getY() + entity.viewHeight / 2f)); + view.setScaleX(entity.scale); + view.setScaleY(entity.scale); + view.setRotation((float) (-entity.rotation / Math.PI * 180)); + } + } + entitiesView.setVisibility(INVISIBLE); + + selectionContainerView = new FrameLayout(context) { + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + return false; + } + }; + addView(selectionContainerView); + + topLayout = new FrameLayout(context); + topLayout.setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(12), AndroidUtilities.dp(12), AndroidUtilities.dp(12)); + topLayout.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int [] {0xff000000, 0x00000000} )); + addView(topLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); + + undoButton = new ImageView(context); + undoButton.setImageResource(R.drawable.photo_undo2); + undoButton.setPadding(AndroidUtilities.dp(3), AndroidUtilities.dp(3), AndroidUtilities.dp(3), AndroidUtilities.dp(3)); + undoButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); + undoButton.setOnClickListener(v -> { + if (renderView != null && renderView.getCurrentBrush() instanceof Brush.Shape) { + renderView.clearShape(); + paintToolsView.setSelectedIndex(1); + onBrushSelected(Brush.BRUSHES_LIST.get(0)); + } else { + undoStore.undo(); + } + }); + undoButton.setAlpha(0.6f); + undoButton.setClickable(false); + topLayout.addView(undoButton, LayoutHelper.createFrame(32, 32, Gravity.TOP | Gravity.LEFT, 12, 0, 0, 0)); + + zoomOutButton = new LinearLayout(context); + zoomOutButton.setOrientation(LinearLayout.HORIZONTAL); + zoomOutButton.setBackground(Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + zoomOutButton.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + zoomOutText = new TextView(context); + zoomOutText.setTextColor(Color.WHITE); + zoomOutText.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + zoomOutText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + zoomOutText.setText(LocaleController.getString(R.string.PhotoEditorZoomOut)); + zoomOutImage = new ImageView(context); + zoomOutImage.setImageResource(R.drawable.photo_zoomout); + zoomOutButton.addView(zoomOutImage, LayoutHelper.createLinear(24, 24, Gravity.CENTER_VERTICAL, 0, 0, 8, 0)); + zoomOutButton.addView(zoomOutText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + zoomOutButton.setAlpha(0); + zoomOutButton.setOnClickListener(e -> { + PhotoViewer.getInstance().zoomOut(); + }); + topLayout.addView(zoomOutButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 32, Gravity.CENTER)); + + undoAllButton = new TextView(context); + undoAllButton.setBackground(Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + undoAllButton.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + undoAllButton.setText(LocaleController.getString(R.string.PhotoEditorClearAll)); + undoAllButton.setGravity(Gravity.CENTER_VERTICAL); + undoAllButton.setTextColor(Color.WHITE); + undoAllButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + undoAllButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + undoAllButton.setOnClickListener(v -> { + if (!undoStore.canUndo()) { + return; + } + if (renderView != null && renderView.getCurrentBrush() instanceof Brush.Shape) { + renderView.clearShape(); + paintToolsView.setSelectedIndex(1); + onBrushSelected(Brush.BRUSHES_LIST.get(0)); + } + renderView.clearAll(); + undoStore.reset(); + entitiesView.removeAllViews(); + }); + undoAllButton.setAlpha(0.6f); + topLayout.addView(undoAllButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 32, Gravity.RIGHT, 0, 0, 4, 0)); + + cancelTextButton = new TextView(context); + cancelTextButton.setBackground(Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + cancelTextButton.setText(LocaleController.getString(R.string.Clear)); + cancelTextButton.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + cancelTextButton.setGravity(Gravity.CENTER_VERTICAL); + cancelTextButton.setTextColor(Color.WHITE); + cancelTextButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + cancelTextButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + cancelTextButton.setOnClickListener(v -> { + if (currentEntityView instanceof TextPaintView) { + AndroidUtilities.hideKeyboard(((TextPaintView) currentEntityView).getFocusedView()); + } + if (emojiViewVisible) { + hideEmojiPopup(false); + } + removeEntity(currentEntityView); + selectEntity(null); + }); + cancelTextButton.setAlpha(0); + cancelTextButton.setVisibility(View.GONE); + topLayout.addView(cancelTextButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 32, Gravity.LEFT | Gravity.TOP, 4, 0, 0, 0)); + + doneTextButton = new TextView(context); + doneTextButton.setBackground(Theme.createSelectorDrawable(0x30ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + doneTextButton.setText(LocaleController.getString(R.string.Done)); + doneTextButton.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + doneTextButton.setGravity(Gravity.CENTER_VERTICAL); + doneTextButton.setTextColor(Color.WHITE); + doneTextButton.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + doneTextButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + doneTextButton.setOnClickListener(v -> { + selectEntity(null); + }); + doneTextButton.setAlpha(0); + doneTextButton.setVisibility(View.GONE); + topLayout.addView(doneTextButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 32, Gravity.RIGHT, 0, 0, 4, 0)); + + bottomLayout = new FrameLayout(context) { + private float lastRainbowX, lastRainbowY; + private Path path = new Path(); + + { + setWillNotDraw(false); + colorPickerRainbowPaint.setStyle(Paint.Style.STROKE); + colorPickerRainbowPaint.setStrokeWidth(AndroidUtilities.dp(2)); + } + + private void checkRainbow(float cx, float cy) { + if (cx != lastRainbowX || cy != lastRainbowY) { + lastRainbowX = cx; + lastRainbowY = cy; + + int[] colors = { + 0xffeb4b4b, + 0xffee82ee, + 0xff6080e4, + Color.CYAN, + 0xff8fce00, + Color.YELLOW, + 0xffffa500, + 0xffeb4b4b + }; + colorPickerRainbowPaint.setShader(new SweepGradient(cx, cy, colors, null)); + } + } + + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + if (overlayLayout != null) { + overlayLayout.invalidate(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + ViewGroup barView = getBarView(); + AndroidUtilities.rectTmp.set( + AndroidUtilities.lerp(barView.getLeft(), colorsListView.getLeft(), toolsTransformProgress), + AndroidUtilities.lerp(barView.getTop(), colorsListView.getTop(), toolsTransformProgress), + AndroidUtilities.lerp(barView.getRight(), colorsListView.getRight(), toolsTransformProgress), + AndroidUtilities.lerp(barView.getBottom(), colorsListView.getBottom(), toolsTransformProgress) + ); + final float radius = AndroidUtilities.lerp(AndroidUtilities.dp(32), AndroidUtilities.dp(24), toolsTransformProgress); + canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, toolsPaint); + + if (barView != null && barView.getChildCount() >= 1 && toolsTransformProgress != 1f) { + canvas.save(); + canvas.translate(barView.getLeft(), barView.getTop()); + + View child = barView.getChildAt(0); + if (barView instanceof PaintTextOptionsView) { + child = ((PaintTextOptionsView) barView).getColorClickableView(); + } + + if (child.getAlpha() != 0f) { + canvas.scale(child.getScaleX(), child.getScaleY(), child.getPivotX(), child.getPivotY()); + + colorPickerRainbowPaint.setAlpha((int) ((1f - toolsTransformProgress) * child.getAlpha() * 0xFF)); + + int childWidth = child.getWidth() - child.getPaddingLeft() - child.getPaddingRight(); + int childHeight = child.getHeight() - child.getPaddingTop() - child.getPaddingBottom(); + float cx = child.getX() + child.getPaddingLeft() + childWidth / 2f, cy = child.getY() + child.getPaddingTop() + childHeight / 2f; + if (tabsNewSelectedIndex != -1) { + ViewGroup barView2 = (ViewGroup) getBarView(tabsNewSelectedIndex); + View newView = (barView2 == null ? barView : barView2).getChildAt(0); + if (barView2 instanceof PaintTextOptionsView) { + newView = ((PaintTextOptionsView) barView2).getColorClickableView(); + } + cx = AndroidUtilities.lerp(cx, newView.getX() + newView.getPaddingLeft() + (newView.getWidth() - newView.getPaddingLeft() - newView.getPaddingRight()) / 2f, tabsSelectionProgress); + cy = AndroidUtilities.lerp(cy, newView.getY() + newView.getPaddingTop() + (newView.getHeight() - newView.getPaddingTop() - newView.getPaddingBottom()) / 2f, tabsSelectionProgress); + } + if (colorsListView != null && colorsListView.getChildCount() > 0) { + View animateToView = colorsListView.getChildAt(0); + cx = AndroidUtilities.lerp(cx, colorsListView.getX() - barView.getLeft() + animateToView.getX() + animateToView.getWidth() / 2f, toolsTransformProgress); + cy = AndroidUtilities.lerp(cy, colorsListView.getY() - barView.getTop() + animateToView.getY() + animateToView.getHeight() / 2f, toolsTransformProgress); + } + checkRainbow(cx, cy); + + float rad = Math.min(childWidth, childHeight) / 2f - AndroidUtilities.dp(0.5f); + if (colorsListView != null && colorsListView.getChildCount() > 0) { + View animateToView = colorsListView.getChildAt(0); + rad = AndroidUtilities.lerp(rad, Math.min(animateToView.getWidth() - animateToView.getPaddingLeft() - animateToView.getPaddingRight(), animateToView.getHeight() - animateToView.getPaddingTop() - animateToView.getPaddingBottom()) / 2f - AndroidUtilities.dp(2f), toolsTransformProgress); + } + AndroidUtilities.rectTmp.set(cx - rad, cy - rad, cx + rad, cy + rad); + canvas.drawArc(AndroidUtilities.rectTmp, 0, 360, false, colorPickerRainbowPaint); + + colorSwatchPaint.setColor(colorSwatch.color); + colorSwatchPaint.setAlpha((int) (colorSwatchPaint.getAlpha() * child.getAlpha())); + colorSwatchOutlinePaint.setColor(colorSwatch.color); + colorSwatchOutlinePaint.setAlpha((int) (0xFF * child.getAlpha())); + + float rad2 = rad - AndroidUtilities.dp(3f); + PaintColorsListView.drawColorCircle(canvas, cx, cy, rad2, colorSwatchPaint.getColor()); + + colorSwatchOutlinePaint.setAlpha((int) (colorSwatchOutlinePaint.getAlpha() * toolsTransformProgress * child.getAlpha())); + canvas.drawCircle(cx, cy, rad - (AndroidUtilities.dp(3f) + colorSwatchOutlinePaint.getStrokeWidth()) * (1f - toolsTransformProgress), colorSwatchOutlinePaint); + } + + canvas.restore(); + } + } + }; + bottomLayout.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), 0); + bottomLayout.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int [] {0x00000000, 0x80000000} )); + addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 44 + 60, Gravity.BOTTOM)); + + paintToolsView = new PaintToolsView(context, originalBitmap != null); + paintToolsView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); + paintToolsView.setDelegate(this); +// paintToolsView.setSelectedIndex(MathUtils.clamp(palette.getCurrentBrush(), 0, Brush.BRUSHES_LIST.size()) + 1); + paintToolsView.setSelectedIndex(1); + bottomLayout.addView(paintToolsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); + + textOptionsView = new PaintTextOptionsView(context); + textOptionsView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); + textOptionsView.setVisibility(GONE); + textOptionsView.setDelegate(this); + textOptionsView.setTypeface(PersistColorPalette.getInstance(currentAccount).getCurrentTypeface()); + textOptionsView.setAlignment(PersistColorPalette.getInstance(currentAccount).getCurrentAlignment()); + bottomLayout.addView(textOptionsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); + + overlayLayout = new FrameLayout(context) { + { + setWillNotDraw(false); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isTypefaceMenuShown) { + showTypefaceMenu(false); + return true; + } + return super.onTouchEvent(event); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + typefaceMenuOutlinePaint.setAlpha((int) (0xFF * 0.4f * textOptionsView.getAlpha() * (1f - typefaceMenuTransformProgress))); + + textOptionsView.getTypefaceCellBounds(AndroidUtilities.rectTmp); + float yOffset = bottomLayout.getTop() + textOptionsView.getTop() + bottomLayout.getTranslationY() + textOptionsView.getTranslationY(); + AndroidUtilities.rectTmp.set(AndroidUtilities.lerp(AndroidUtilities.rectTmp.left, typefaceListView.getLeft(), typefaceMenuTransformProgress), + AndroidUtilities.lerp(yOffset + AndroidUtilities.rectTmp.top, typefaceListView.getTop() - typefaceListView.getTranslationY(), typefaceMenuTransformProgress), + AndroidUtilities.lerp(AndroidUtilities.rectTmp.right, typefaceListView.getRight(), typefaceMenuTransformProgress), + AndroidUtilities.lerp(yOffset + AndroidUtilities.rectTmp.bottom, typefaceListView.getBottom() - typefaceListView.getTranslationY(), typefaceMenuTransformProgress)); + float rad = AndroidUtilities.dp(AndroidUtilities.lerp(32, 16, typefaceMenuTransformProgress)); + + int alpha = typefaceMenuBackgroundPaint.getAlpha(); + typefaceMenuBackgroundPaint.setAlpha((int) (alpha * typefaceMenuTransformProgress)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, typefaceMenuBackgroundPaint); + typefaceMenuBackgroundPaint.setAlpha(alpha); + + canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, typefaceMenuOutlinePaint); + } + }; + addView(overlayLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + typefaceListView = new PaintTypefaceListView(context); + typefaceListView.setVisibility(GONE); + typefaceListView.setOnItemClickListener((view, position) -> { + PaintTypeface typeface = PaintTypeface.get().get(position); + textOptionsView.setTypeface(typeface.getKey()); + onTypefaceSelected(typeface); + showTypefaceMenu(false); + }); + textOptionsView.setTypefaceListView(typefaceListView); + overlayLayout.addView(typefaceListView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 8, 8)); + + typefaceMenuOutlinePaint.setStyle(Paint.Style.STROKE); + typefaceMenuOutlinePaint.setColor(0x66FFFFFF); + typefaceMenuOutlinePaint.setStrokeWidth(Math.max(2, AndroidUtilities.dp(1))); + + typefaceMenuBackgroundPaint.setColor(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); + + colorsListView = new PaintColorsListView(context) { + private Path path = new Path(); + + @Override + public void draw(Canvas c) { + ViewGroup barView = getBarView(); + AndroidUtilities.rectTmp.set( + AndroidUtilities.lerp(barView.getLeft() - getLeft(), 0, toolsTransformProgress), + AndroidUtilities.lerp(barView.getTop() - getTop(), 0, toolsTransformProgress), + AndroidUtilities.lerp(barView.getRight() - getLeft(), getWidth(), toolsTransformProgress), + AndroidUtilities.lerp(barView.getBottom() - getTop(), getHeight(), toolsTransformProgress) + ); + + path.rewind(); + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(32), AndroidUtilities.dp(32), Path.Direction.CW); + + c.save(); + c.clipPath(path); + super.draw(c); + c.restore(); + } + }; + colorsListView.setVisibility(GONE); + colorsListView.setColorPalette(PersistColorPalette.getInstance(currentAccount)); + colorsListView.setColorListener(color -> { + setNewColor(color); + showColorList(false); + }); + bottomLayout.addView(colorsListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 84, Gravity.TOP, 56, 0, 56, 6)); + + setupTabsLayout(context); + + cancelButton = new PaintCancelView(context); + cancelButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + cancelButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider))); + bottomLayout.addView(cancelButton, LayoutHelper.createFrame(32, 32, Gravity.BOTTOM | Gravity.LEFT, 12, 0, 0, 4)); + + doneButton = new PaintDoneView(context); + doneButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); + doneButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider))); + doneButton.setOnClickListener(v -> { + if (isColorListShown) { + new ColorPickerBottomSheet(context, this.resourcesProvider).setColor(colorSwatch.color).setPipetteDelegate(new ColorPickerBottomSheet.PipetteDelegate() { + private boolean hasPipette; + + @Override + public void onStartColorPipette() { + hasPipette = true; + } + + @Override + public void onStopColorPipette() { + hasPipette = false; + } + + @Override + public ViewGroup getContainerView() { + return pipetteContainerLayout; + } + + @Override + public View getSnapshotDrawingView() { + return LPhotoPaintView.this; + } + + @Override + public void onDrawImageOverCanvas(Bitmap bitmap, Canvas canvas) { + Matrix matrix = renderView.getMatrix(); + canvas.save(); + canvas.translate(renderView.getX(), renderView.getY()); + canvas.concat(matrix); + canvas.scale(renderView.getWidth() / (float) originalBitmap.getWidth(), renderView.getHeight() / (float) originalBitmap.getHeight(), 0, 0); + canvas.drawBitmap(originalBitmap, 0, 0, null); + canvas.restore(); + } + + @Override + public boolean isPipetteVisible() { + return hasPipette; + } + + @Override + public boolean isPipetteAvailable() { + // TODO: Get bitmap from VideoPlayer to support videos + return originalBitmap != null; + } + + @Override + public void onColorSelected(int color) { + showColorList(false); + + PersistColorPalette.getInstance(currentAccount).selectColor(color); + PersistColorPalette.getInstance(currentAccount).saveColors(); + setNewColor(color); + colorsListView.getAdapter().notifyDataSetChanged(); + } + }).setColorListener(color -> { + PersistColorPalette.getInstance(currentAccount).selectColor(color); + PersistColorPalette.getInstance(currentAccount).saveColors(); + setNewColor(color); + colorsListView.getAdapter().notifyDataSetChanged(); + }).show(); + return; + } + if (onDoneButtonClickedListener != null) { + onDoneButtonClickedListener.run(); + } + }); + bottomLayout.addView(doneButton, LayoutHelper.createFrame(32, 32, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, 12, 4)); + + weightChooserView = new PaintWeightChooserView(context); + weightChooserView.setColorSwatch(colorSwatch); + weightChooserView.setRenderView(renderView); + weightChooserView.setValueOverride(weightDefaultValueOverride); + colorSwatch.brushWeight = weightDefaultValueOverride.get(); + weightChooserView.setOnUpdate(()-> { + setCurrentSwatch(colorSwatch, true); + PersistColorPalette.getInstance(currentAccount).setCurrentWeight(colorSwatch.brushWeight); + }); + addView(weightChooserView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + pipetteContainerLayout = new FrameLayout(context); + addView(pipetteContainerLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + colorSwatchOutlinePaint.setStyle(Paint.Style.STROKE); + colorSwatchOutlinePaint.setStrokeWidth(AndroidUtilities.dp(2)); + + setCurrentSwatch(colorSwatch, true); +// onBrushSelected(Brush.BRUSHES_LIST.get(MathUtils.clamp(palette.getCurrentBrush(), 0, Brush.BRUSHES_LIST.size()))); + onBrushSelected(Brush.BRUSHES_LIST.get(0)); + updateColors(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + setSystemGestureExclusionRects(Arrays.asList(new Rect(0, (int) (AndroidUtilities.displaySize.y * .35f), AndroidUtilities.dp(100), (int) (AndroidUtilities.displaySize.y * .65)))); + } + } + + private void setNewColor(int color) { + int wasColor = colorSwatch.color; + colorSwatch.color = color; + setCurrentSwatch(colorSwatch, true); + + ValueAnimator animator = ValueAnimator.ofFloat(0, 1).setDuration(150); + animator.addUpdateListener(animation -> { + float val = (float) animation.getAnimatedValue(); + + colorSwatch.color = ColorUtils.blendARGB(wasColor, color, val); + bottomLayout.invalidate(); + }); + animator.start(); + } + + private TextPaintView createText(boolean select) { + onTextAdd(); + + Size paintingSize = getPaintingSize(); + Point position = startPositionRelativeToEntity(null); + TextPaintView view = new TextPaintView(getContext(), position, (int) (paintingSize.width / 9), "", colorSwatch, selectedTextType); + if (position.x == entitiesView.getMeasuredWidth() / 2f) { + view.setHasStickyX(true); + } + if (position.y == entitiesView.getMeasuredHeight() / 2f) { + view.setHasStickyY(true); + } + view.setDelegate(this); + view.setMaxWidth((int) (paintingSize.width - 20)); + view.setTypeface(PersistColorPalette.getInstance(currentAccount).getCurrentTypeface()); + view.setType(PersistColorPalette.getInstance(currentAccount).getCurrentTextType()); + entitiesView.addView(view, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + if (currentCropState != null) { + view.scale(1.0f / currentCropState.cropScale); + view.rotate(-(currentCropState.transformRotation + currentCropState.cropRotate)); + } + + if (select) { + registerRemovalUndo(view); + + view.beginEditing(); + selectEntity(view, false); + view.getFocusedView().requestFocus(); + AndroidUtilities.showKeyboard(view.getFocusedView()); + editingText = true; + textOptionsView.setAlignment(PersistColorPalette.getInstance(currentAccount).getCurrentAlignment(), true); + textOptionsView.setOutlineType(PersistColorPalette.getInstance(currentAccount).getCurrentTextType()); + } + return view; + } + + @Override + public void setOnDoneButtonClickedListener(Runnable callback) { + onDoneButtonClickedListener = callback; + } + + private void editSelectedTextEntity() { + if (!(currentEntityView instanceof TextPaintView) || editingText) { + return; + } + + TextPaintView textPaintView = (TextPaintView) currentEntityView; + editingText = true; + + textPaintView.beginEditing(); + View view = textPaintView.getFocusedView(); + view.requestFocus(); + AndroidUtilities.showKeyboard(view); + } + + private boolean zoomOutVisible = false; + @Override + public void updateZoom(boolean zoomedOut) { + boolean shouldBeVisible = !zoomedOut; + if (zoomOutVisible != shouldBeVisible) { + zoomOutVisible = shouldBeVisible; + zoomOutButton.animate().cancel(); + zoomOutButton.animate().alpha(zoomedOut ? 0f : 1f).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).setDuration(240).start(); + } + } + + private boolean selectEntity(EntityView entityView) { + return selectEntity(entityView, true); + } + + private boolean selectEntity(EntityView entityView, boolean changeOptions) { + boolean changed = false; + + boolean animatingToTextTab = false; + if (entityView instanceof TextPaintView && (tabsNewSelectedIndex == -1 && tabsSelectedIndex != 2 || tabsNewSelectedIndex != -1 && tabsNewSelectedIndex != 2)) { + if (tabsSelectionAnimator != null && tabsNewSelectedIndex != 2) { + tabsSelectionAnimator.cancel(); + } + if (isColorListShown) { + showColorList(false); + } + switchTab(2); + animatingToTextTab = true; + } + + if (entityView instanceof TextPaintView && changeOptions) { + int align; + switch (((TextPaintView) entityView).getEditText().getGravity()) { + default: + case Gravity.LEFT | Gravity.CENTER_VERTICAL: + align = PaintTextOptionsView.ALIGN_LEFT; + break; + case Gravity.CENTER: + align = PaintTextOptionsView.ALIGN_CENTER; + break; + case Gravity.RIGHT | Gravity.CENTER_VERTICAL: + align = PaintTextOptionsView.ALIGN_RIGHT; + break; + } + textOptionsView.setAlignment(align); + textOptionsView.setTypeface(((TextPaintView) entityView).getTypeface().getKey()); + textOptionsView.setOutlineType(((TextPaintView) entityView).getType(), true); + overlayLayout.invalidate(); + } + + if (currentEntityView != null) { + if (currentEntityView == entityView) { + if (!editingText) { + showMenuForEntity(currentEntityView); + } else if (currentEntityView instanceof TextPaintView) { + AndroidUtilities.showKeyboard(((TextPaintView) currentEntityView).getFocusedView()); + hideEmojiPopup(false); + } + return true; + } else { + currentEntityView.deselect(); + if (currentEntityView instanceof TextPaintView) { + ((TextPaintView) currentEntityView).endEditing(); + if (!(entityView instanceof TextPaintView)) { + editingText = false; + AndroidUtilities.hideKeyboard(((TextPaintView) currentEntityView).getFocusedView()); + hideEmojiPopup(false); + } + } + } + changed = true; + } + + EntityView oldEntity = currentEntityView; + currentEntityView = entityView; + if (oldEntity instanceof TextPaintView) { + TextPaintView textPaintView = (TextPaintView) oldEntity; + if (TextUtils.isEmpty(textPaintView.getText())) { + removeEntity(oldEntity); + } + } + + if (currentEntityView != null) { + currentEntityView.select(selectionContainerView); + entitiesView.bringChildToFront(currentEntityView); + + if (currentEntityView instanceof TextPaintView) { + TextPaintView textPaintView = (TextPaintView) currentEntityView; + textPaintView.getSwatch().brushWeight = colorSwatch.brushWeight; + setCurrentSwatch(textPaintView.getSwatch(), true); + + float base = (int) (paintingSize.width / 9); + weightChooserView.setValueOverride(new PaintWeightChooserView.ValueOverride() { + @Override + public float get() { + return textPaintView.getBaseFontSize() / base; + } + + @Override + public void set(float val) { + textPaintView.setBaseFontSize((int) (base * val)); + } + }); + weightChooserView.setShowPreview(false); + } else { + weightChooserView.setValueOverride(weightDefaultValueOverride); + weightChooserView.setShowPreview(true); + colorSwatch.brushWeight = weightDefaultValueOverride.get(); + setCurrentSwatch(colorSwatch, true); + } + + changed = true; + } else { + if (tabsSelectionAnimator != null && tabsNewSelectedIndex != 0) { + tabsSelectionAnimator.cancel(); + } + if (isColorListShown) { + showColorList(false); + } + switchTab(0); + + weightChooserView.setValueOverride(weightDefaultValueOverride); + weightChooserView.setShowPreview(true); + colorSwatch.brushWeight = weightDefaultValueOverride.get(); + setCurrentSwatch(colorSwatch, true); + } + + return changed; + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + boolean restore = false; + if ((child == renderView || child == renderInputView || child == entitiesView || child == selectionContainerView) && currentCropState != null) { + canvas.save(); + + int status = (Build.VERSION.SDK_INT >= 21 && !inBubbleMode ? AndroidUtilities.statusBarHeight : 0); + int actionBarHeight = ActionBar.getCurrentActionBarHeight(); + int actionBarHeight2 = actionBarHeight + status; + + int vw = child.getMeasuredWidth(); + int vh = child.getMeasuredHeight(); + int tr = currentCropState.transformRotation; + if (tr == 90 || tr == 270) { + int temp = vw; + vw = vh; + vh = temp; + } + + int w = (int) (vw * currentCropState.cropPw * child.getScaleX() / currentCropState.cropScale); + int h = (int) (vh * currentCropState.cropPh * child.getScaleY() / currentCropState.cropScale); + float x = (float) Math.ceil((getMeasuredWidth() - w) / 2f) + transformX; + float y = (getMeasuredHeight() - actionBarHeight2 - AndroidUtilities.dp(48) + getAdditionalBottom() - h) / 2f + AndroidUtilities.dp(8) + status + transformY; + + canvas.clipRect(Math.max(0, x), Math.max(0, y), Math.min(x + w, getMeasuredWidth()), Math.min(getMeasuredHeight(), y + h)); + restore = true; + } + boolean result = super.drawChild(canvas, child, drawingTime); + if (restore) { + canvas.restore(); + } + return result; + } + + private ViewGroup getBarView() { + return tabsSelectedIndex == 2 ? textOptionsView : paintToolsView; + } + + private void setupTabsLayout(Context context) { + tabsLayout = new LinearLayout(context) { + Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + { + linePaint.setStrokeWidth(AndroidUtilities.dp(2)); + linePaint.setStyle(Paint.Style.STROKE); + linePaint.setStrokeCap(Paint.Cap.ROUND); + + setWillNotDraw(false); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + TextView selectedTab = (TextView) getChildAt(tabsSelectedIndex); + TextView newSelectedTab = tabsNewSelectedIndex != -1 ? (TextView) getChildAt(tabsNewSelectedIndex) : null; + linePaint.setColor(selectedTab.getCurrentTextColor()); + float y = selectedTab.getY() + selectedTab.getHeight() - selectedTab.getPaddingBottom() + AndroidUtilities.dp(3); + Layout layout = selectedTab.getLayout(); + Layout newLayout = newSelectedTab != null ? newSelectedTab.getLayout() : null; + float pr = newLayout == null ? 0 : CubicBezierInterpolator.DEFAULT.getInterpolation(tabsSelectionProgress); + float x = AndroidUtilities.lerp(selectedTab.getX() + layout.getPrimaryHorizontal(layout.getLineStart(0)), newSelectedTab != null ? newSelectedTab.getX() + newLayout.getPrimaryHorizontal(layout.getLineStart(0)) : 0, pr); + float width = AndroidUtilities.lerp(layout.getPrimaryHorizontal(layout.getLineEnd(0)) - layout.getPrimaryHorizontal(layout.getLineStart(0)), newLayout != null ? newLayout.getPrimaryHorizontal(newLayout.getLineEnd(0)) - newLayout.getPrimaryHorizontal(newLayout.getLineStart(0)) : 0, pr); + canvas.drawLine(x, y, x + width, y, linePaint); + } + }; + tabsLayout.setClipToPadding(false); + tabsLayout.setOrientation(LinearLayout.HORIZONTAL); + bottomLayout.addView(tabsLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 32 + 8, Gravity.BOTTOM, 52, 0, 52, 0)); + + drawTab = new TextView(context); + drawTab.setText(LocaleController.getString(R.string.PhotoEditorDraw).toUpperCase()); + drawTab.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + drawTab.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + drawTab.setTextColor(Color.WHITE); + drawTab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + drawTab.setGravity(Gravity.CENTER_HORIZONTAL); + drawTab.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + drawTab.setOnClickListener(v -> { + if (editingText) { + selectEntity(null); + } else { + switchTab(0); + } + }); + tabsLayout.addView(drawTab, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f)); + + stickerTab = new TextView(context); + stickerTab.setText(LocaleController.getString(R.string.PhotoEditorSticker).toUpperCase()); + stickerTab.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + stickerTab.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + stickerTab.setOnClickListener(v -> openStickersView()); + stickerTab.setTextColor(Color.WHITE); + stickerTab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + stickerTab.setGravity(Gravity.CENTER_HORIZONTAL); + stickerTab.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + stickerTab.setAlpha(0.6f); + tabsLayout.addView(stickerTab, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f)); + + textTab = new TextView(context); + textTab.setText(LocaleController.getString(R.string.PhotoEditorText).toUpperCase()); + textTab.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + textTab.setPadding(0, AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8)); + textTab.setTextColor(Color.WHITE); + textTab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textTab.setGravity(Gravity.CENTER_HORIZONTAL); + textTab.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textTab.setAlpha(0.6f); + textTab.setOnClickListener(v -> { + switchTab(2); + if (!(currentEntityView instanceof TextPaintView)) { + createText(true); + } + }); + tabsLayout.addView(textTab, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f)); + } + + private View getBarView(int index) { + if (index == 0) + return paintToolsView; + if (index == 2) + return textOptionsView; + return null; + } + + private void switchTab(int index) { + if (tabsSelectedIndex == index || tabsNewSelectedIndex == index) { + return; + } + if (tabsSelectionAnimator != null) { + tabsSelectionAnimator.cancel(); + } + + final View view = getBarView(tabsSelectedIndex); + tabsNewSelectedIndex = index; + final View newView = getBarView(tabsNewSelectedIndex); + + tabsSelectionAnimator = ValueAnimator.ofFloat(0, 1).setDuration(300); + tabsSelectionAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + tabsSelectionAnimator.addUpdateListener(animation -> { + tabsSelectionProgress = (float) animation.getAnimatedValue(); + tabsLayout.invalidate(); + bottomLayout.invalidate(); + overlayLayout.invalidate(); + + for (int i = 0; i < tabsLayout.getChildCount(); i++) { + tabsLayout.getChildAt(i).setAlpha(0.6f + 0.4f * (i == tabsNewSelectedIndex ? tabsSelectionProgress : i == tabsSelectedIndex ? 1f - tabsSelectionProgress : 0f)); + } + float pr = CubicBezierInterpolator.DEFAULT.getInterpolation(tabsSelectionProgress); + + if (view != null && newView != null) { + float scale = 0.6f + 0.4f * (1f - pr); + view.setScaleX(scale); + view.setScaleY(scale); + view.setTranslationY(AndroidUtilities.dp(16) * Math.min(pr, 0.25f) / 0.25f); + view.setAlpha(1f - Math.min(pr, 0.25f) / 0.25f); + + scale = 0.6f + 0.4f * pr; + newView.setScaleX(scale); + newView.setScaleY(scale); + newView.setTranslationY(-AndroidUtilities.dp(16) * Math.min(1f - pr, 0.25f) / 0.25f); + newView.setAlpha(1f - Math.min(1f - pr, 0.25f) / 0.25f); + } + }); + tabsSelectionAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + if (view != null && newView != null) { + newView.setVisibility(VISIBLE); + } + if (index == 2) { + weightChooserView.setMinMax(0.5f, 2f); + } else { + Brush brush = renderView.getCurrentBrush(); + if (brush instanceof Brush.Blurer || brush instanceof Brush.Eraser) { + weightChooserView.setMinMax(0.4f, 1.75f); + } else { + weightChooserView.setMinMax(0.05f, 1f); + } + } + } + + @Override + public void onAnimationEnd(Animator animation) { + tabsSelectedIndex = tabsNewSelectedIndex; + tabsNewSelectedIndex = -1; + tabsLayout.invalidate(); + + if (view != null && newView != null) { + view.setVisibility(GONE); + } + + if (animation == tabsSelectionAnimator) { + tabsSelectionAnimator = null; + } + } + }); + tabsSelectionAnimator.start(); + } + + private void openStickersView() { + final int wasSelectedIndex = tabsSelectedIndex; + switchTab(1); +// postDelayed(() -> { +// if (facesBitmap != null) { +// detectFaces(); +// } +// }, 350); + StickerMasksAlert stickerMasksAlert = new StickerMasksAlert(getContext(), facesBitmap == null, resourcesProvider) { + @Override + public void onDismissAnimationStart() { + super.onDismissAnimationStart(); + switchTab(wasSelectedIndex); + } + }; + stickerMasksAlert.setDelegate((parentObject, sticker) -> createSticker(parentObject, sticker, true)); + stickerMasksAlert.setOnDismissListener(dialog -> { + onOpenCloseStickersAlert(false); + switchTab(wasSelectedIndex); + }); + stickerMasksAlert.show(); + onOpenCloseStickersAlert(true); + } + + protected void onOpenCloseStickersAlert(boolean open) {} + + protected void onTextAdd() {} + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + + setMeasuredDimension(width, height); + + float bitmapW; + float bitmapH; + int fullHeight = AndroidUtilities.displaySize.y - ActionBar.getCurrentActionBarHeight() - getAdditionalTop() - getAdditionalBottom(); + int maxHeight = fullHeight - AndroidUtilities.dp(48); + if (bitmapToEdit != null) { + bitmapW = bitmapToEdit.getWidth(); + bitmapH = bitmapToEdit.getHeight(); + } else { + bitmapW = width; + bitmapH = height - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(48); + } + + float renderWidth = width; + float renderHeight = (float) Math.floor(renderWidth * bitmapH / bitmapW); + if (renderHeight > maxHeight) { + renderHeight = maxHeight; + renderWidth = (float) Math.floor(renderHeight * bitmapW / bitmapH); + } + + renderView.measure(MeasureSpec.makeMeasureSpec((int) renderWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) renderHeight, MeasureSpec.EXACTLY)); + renderInputView.measure(MeasureSpec.makeMeasureSpec((int) renderWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) renderHeight, MeasureSpec.EXACTLY)); + + baseScale = renderWidth / paintingSize.width; + entitiesView.setScaleX(baseScale); + entitiesView.setScaleY(baseScale); + entitiesView.measure(MeasureSpec.makeMeasureSpec((int) paintingSize.width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) paintingSize.height, MeasureSpec.EXACTLY)); + if (currentEntityView != null) { + currentEntityView.updateSelectionView(); + } + selectionContainerView.measure(MeasureSpec.makeMeasureSpec((int) renderWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) renderHeight, MeasureSpec.EXACTLY)); + measureChild(bottomLayout, widthMeasureSpec, heightMeasureSpec); + measureChild(weightChooserView, widthMeasureSpec, heightMeasureSpec); + measureChild(pipetteContainerLayout, widthMeasureSpec, heightMeasureSpec); + measureChild(overlayLayout, widthMeasureSpec, heightMeasureSpec); + + topLayout.setPadding(topLayout.getPaddingLeft(), AndroidUtilities.dp(12) + AndroidUtilities.statusBarHeight, topLayout.getPaddingRight(), topLayout.getPaddingBottom()); + measureChild(topLayout, widthMeasureSpec, heightMeasureSpec); + ignoreLayout = false; + + int keyboardSize = SharedConfig.smoothKeyboard ? 0 : measureKeyboardHeight(); + if (!waitingForKeyboardOpen && keyboardSize <= AndroidUtilities.dp(20) && !emojiViewVisible && !isAnimatePopupClosing) { + ignoreLayout = true; + hideEmojiView(); + ignoreLayout = false; + } + + if (keyboardSize <= AndroidUtilities.dp(20)) { + + } else { + hideEmojiView(); + } + + if (emojiView != null) { + measureChild(emojiView, widthMeasureSpec, heightMeasureSpec); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + int width = right - left; + int height = bottom - top; + + if (emojiView != null) { + int childLeft = 0, childTop; + if (AndroidUtilities.isTablet()) { + childTop = height - emojiView.getMeasuredHeight(); + } else { + childTop = height + measureKeyboardHeight() - emojiView.getMeasuredHeight(); + } + emojiView.layout(childLeft, childTop, childLeft + emojiView.getMeasuredWidth(), childTop + emojiView.getMeasuredHeight()); + } + + int status = (Build.VERSION.SDK_INT >= 21 && !inBubbleMode ? AndroidUtilities.statusBarHeight : 0); + int actionBarHeight = ActionBar.getCurrentActionBarHeight(); + int actionBarHeight2 = actionBarHeight + status; + + int x = (int) Math.ceil((width - renderView.getMeasuredWidth()) / 2f); + int y = (height - actionBarHeight2 - AndroidUtilities.dp(48) - renderView.getMeasuredHeight()) / 2 + AndroidUtilities.dp(8) + status + (getAdditionalTop() - getAdditionalBottom()) / 2; + + renderView.layout(x, y, x + renderView.getMeasuredWidth(), y + renderView.getMeasuredHeight()); + renderInputView.layout(x, y, x + renderInputView.getMeasuredWidth(), y + renderInputView.getMeasuredHeight()); + int x2 = x + (renderView.getMeasuredWidth() - entitiesView.getMeasuredWidth()) / 2; + int y2 = y + (renderView.getMeasuredHeight() - entitiesView.getMeasuredHeight()) / 2; + entitiesView.layout(x2, y2, x2 + entitiesView.getMeasuredWidth(), y2 + entitiesView.getMeasuredHeight()); + selectionContainerView.layout(x, y, x + selectionContainerView.getMeasuredWidth(), y + selectionContainerView.getMeasuredHeight()); + } + + private Size getPaintingSize() { + if (paintingSize != null) { + return paintingSize; + } + float width = bitmapToEdit.getWidth(); + float height = bitmapToEdit.getHeight(); + + int maxSide; + switch (SharedConfig.getDevicePerformanceClass()) { + case SharedConfig.PERFORMANCE_CLASS_LOW: + maxSide = 1280; + break; + default: + case SharedConfig.PERFORMANCE_CLASS_AVERAGE: + maxSide = 2560; + break; + case SharedConfig.PERFORMANCE_CLASS_HIGH: + maxSide = 3840; + break; + } + Size size = new Size(width, height); + size.width = maxSide; + size.height = (float) Math.floor(size.width * height / width); + if (size.height > maxSide) { + size.height = maxSide; + size.width = (float) Math.floor(size.height * width / height); + } + paintingSize = size; + return size; + } + + @Override + public void init() { + entitiesView.setVisibility(VISIBLE); + renderView.setVisibility(View.VISIBLE); + renderInputView.setVisibility(View.VISIBLE); + } + +// private int getFrameRotation() { +// switch (originalBitmapRotation) { +// case 90: return Frame.ROTATION_90; +// case 180: return Frame.ROTATION_180; +// case 270: return Frame.ROTATION_270; +// default: return Frame.ROTATION_0; +// } +// } + + private boolean isSidewardOrientation() { + return originalBitmapRotation % 360 == 90 || originalBitmapRotation % 360 == 270; + } + + private void detectFaces() { + } + + @Override + public void shutdown() { + renderView.shutdown(); + entitiesView.setVisibility(GONE); + selectionContainerView.setVisibility(GONE); + + queue.postRunnable(() -> { + Looper looper = Looper.myLooper(); + if (looper != null) { + looper.quit(); + } + }); + } + + @Override + public void onResume() { + renderView.redraw(); + } + + @Override + public void setOffsetTranslationY(float y, float progress, int keyboardHeight, boolean isPan) { + offsetTranslationY = y; + if (!isPan) { + topLayout.setTranslationY(-y); + + if (tabsSelectedIndex == 0) { + weightChooserView.setTranslationX(-y); + } + + bottomLayout.setTranslationY(y); + } else { + setTranslationY(0); + } + } + + @Override + public float getOffsetTranslationY() { + return offsetTranslationY; + } + + @Override + public void updateColors() { + toolsPaint.setColor(0xff191919); + } + + @Override + public boolean hasChanges() { + return undoStore.canUndo(); + } + + @Override + public Bitmap getBitmap(ArrayList entities, Bitmap[] thumbBitmap) { + Bitmap bitmap = renderView.getResultBitmap(); + lcm = BigInteger.ONE; + if (bitmap != null && entitiesView.entitiesCount() > 0) { + Canvas canvas; + Canvas thumbCanvas = null; + int count = entitiesView.getChildCount(); + for (int i = 0; i < count; i++) { + boolean skipDrawToBitmap = false; + View v = entitiesView.getChildAt(i); + if (!(v instanceof EntityView)) { + continue; + } + EntityView entity = (EntityView) v; + Point position = entity.getPosition(); + if (entities != null) { + VideoEditedInfo.MediaEntity mediaEntity = new VideoEditedInfo.MediaEntity(); + if (entity instanceof TextPaintView) { + mediaEntity.type = 1; + TextPaintView textPaintView = (TextPaintView) entity; + CharSequence text = textPaintView.getText(); + if (text instanceof Spanned) { + Spanned spanned = (Spanned) text; + AnimatedEmojiSpan[] spans = spanned.getSpans(0, text.length(), AnimatedEmojiSpan.class); + if (spans != null) { + for (int j = 0; j < spans.length; ++j) { + AnimatedEmojiSpan span = spans[j]; + TLRPC.Document document = span.document; + if (document == null) { + document = AnimatedEmojiDrawable.findDocument(currentAccount, span.getDocumentId()); + } + if (document != null) { + AnimatedEmojiDrawable.getDocumentFetcher(currentAccount).putDocument(document); + } + + VideoEditedInfo.EmojiEntity tlentity = new VideoEditedInfo.EmojiEntity(); + tlentity.document_id = span.getDocumentId(); + tlentity.document = document; + tlentity.offset = spanned.getSpanStart(span); + tlentity.length = spanned.getSpanEnd(span) - tlentity.offset; + if (MessageObject.isVideoSticker(document)) { + tlentity.documentAbsolutePath = FileLoader.getInstance(currentAccount).getPathToAttach(document, true).getAbsolutePath(); + } + mediaEntity.entities.add(tlentity); + + if (document != null) { + long duration = 5000; // TODO(dkaraush) + if (duration != 0) { + BigInteger x = BigInteger.valueOf(duration); + lcm = lcm.multiply(x).divide(lcm.gcd(x)); + } + } + } + } + if (!mediaEntity.entities.isEmpty()) { + skipDrawToBitmap = true; + } + } + mediaEntity.text = text.toString(); + int type = textPaintView.getType(); + if (type == 0) { + mediaEntity.subType |= 1; + } else if (type == 2) { + mediaEntity.subType |= 4; + } + mediaEntity.color = textPaintView.getSwatch().color; + mediaEntity.fontSize = textPaintView.getTextSize(); + mediaEntity.textTypeface = textPaintView.getTypeface(); + mediaEntity.textAlign = textPaintView.getAlign(); + skipDrawToBitmap = true; + } else if (entity instanceof StickerView) { + mediaEntity.type = 0; + StickerView stickerView = (StickerView) entity; + Size size = stickerView.getBaseSize(); + mediaEntity.width = size.width; + mediaEntity.height = size.height; + mediaEntity.document = stickerView.getSticker(); + mediaEntity.parentObject = stickerView.getParentObject(); + TLRPC.Document document = stickerView.getSticker(); + mediaEntity.text = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(document, true).getAbsolutePath(); + if (MessageObject.isAnimatedStickerDocument(document, true) || MessageObject.isVideoStickerDocument(document)) { + boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(document, true); + mediaEntity.subType |= isAnimatedSticker ? 1 : 4; + long duration; + if (isAnimatedSticker) { + duration = stickerView.getDuration(); + } else { + duration = 5000; + } + if (duration != 0) { + BigInteger x = BigInteger.valueOf(duration); + lcm = lcm.multiply(x).divide(lcm.gcd(x)); + } + } + skipDrawToBitmap = true; + if (stickerView.isMirrored()) { + mediaEntity.subType |= 2; + } + } else { + continue; + } + entities.add(mediaEntity); + float scaleX = v.getScaleX(); + float scaleY = v.getScaleY(); + float x = v.getX(); + float y = v.getY(); + mediaEntity.viewWidth = v.getWidth(); + mediaEntity.viewHeight = v.getHeight(); + mediaEntity.width = v.getWidth() * scaleX / (float) entitiesView.getMeasuredWidth(); + mediaEntity.height = v.getHeight() * scaleY / (float) entitiesView.getMeasuredHeight(); + mediaEntity.x = (x + v.getWidth() * (1 - scaleX) / 2) / entitiesView.getMeasuredWidth(); + mediaEntity.y = (y + v.getHeight() * (1 - scaleY) / 2) / entitiesView.getMeasuredHeight(); + mediaEntity.rotation = (float) (-v.getRotation() * (Math.PI / 180)); + + mediaEntity.textViewX = (x + v.getWidth() / 2f) / (float) entitiesView.getMeasuredWidth(); + mediaEntity.textViewY = (y + v.getHeight() / 2f) / (float) entitiesView.getMeasuredHeight(); + mediaEntity.textViewWidth = mediaEntity.viewWidth / (float) entitiesView.getMeasuredWidth(); + mediaEntity.textViewHeight = mediaEntity.viewHeight / (float) entitiesView.getMeasuredHeight(); + mediaEntity.scale = scaleX; + + if (thumbBitmap[0] == null) { + thumbBitmap[0] = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); + thumbCanvas = new Canvas(thumbBitmap[0]); + thumbCanvas.drawBitmap(bitmap, 0, 0, null); + } + } + canvas = new Canvas(bitmap); + for (int k = 0; k < 2; k++) { + Canvas currentCanvas = k == 0 ? canvas : thumbCanvas; + if (currentCanvas == null || (k == 0 && skipDrawToBitmap)) { + continue; + } + currentCanvas.save(); + currentCanvas.translate(position.x, position.y); + currentCanvas.scale(v.getScaleX(), v.getScaleY()); + currentCanvas.rotate(v.getRotation()); + currentCanvas.translate(-entity.getWidth() / 2f, -entity.getHeight() / 2f); + if (v instanceof TextPaintView) { + Bitmap b = Bitmaps.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(b); + v.draw(c); + currentCanvas.drawBitmap(b, null, new Rect(0, 0, b.getWidth(), b.getHeight()), null); + try { + c.setBitmap(null); + } catch (Exception e) { + FileLog.e(e); + } + b.recycle(); + } else { + v.draw(currentCanvas); + } + currentCanvas.restore(); + } + } + } + return bitmap; + } + + @Override + public void onCleanupEntities() { + entitiesView.removeAllViews(); + } + + @Override + public long getLcm() { + return lcm.longValue(); + } + + @Override + public View getDoneView() { + return doneButton; + } + + @Override + public View getCancelView() { + return cancelButton; + } + + @Override + public void maybeShowDismissalAlert(PhotoViewer photoViewer, Activity parentActivity, Runnable okRunnable) { + if (isColorListShown) { + showColorList(false); + return; + } + + if (emojiViewVisible) { + hideEmojiPopup(true); + return; + } + + if (editingText) { + selectEntity(null); + return; + } + + if (hasChanges()) { + if (parentActivity == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity, resourcesProvider); + builder.setMessage(LocaleController.getString("PhotoEditorDiscardAlert", R.string.PhotoEditorDiscardAlert)); + builder.setTitle(LocaleController.getString("DiscardChanges", R.string.DiscardChanges)); + builder.setPositiveButton(LocaleController.getString("PassportDiscard", R.string.PassportDiscard), (dialogInterface, i) -> okRunnable.run()); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + photoViewer.showAlertDialog(builder); + } else { + okRunnable.run(); + } + } + + @Override + public boolean onTouch(MotionEvent ev) { + if (currentEntityView != null) { + selectEntity(null); + } + + float x2 = (ev.getX() - renderView.getTranslationX() - getMeasuredWidth() / 2f) / renderView.getScaleX(); + float y2 = (ev.getY() - renderView.getTranslationY() - getMeasuredHeight() / 2f + AndroidUtilities.dp(32) - (getAdditionalTop() - getAdditionalBottom()) / 2f) / renderView.getScaleY(); + float rotation = (float) Math.toRadians(-renderView.getRotation()); + float x = (float) (x2 * Math.cos(rotation) - y2 * Math.sin(rotation)) + renderView.getMeasuredWidth() / 2f; + float y = (float) (x2 * Math.sin(rotation) + y2 * Math.cos(rotation)) + renderView.getMeasuredHeight() / 2f; + + MotionEvent event = MotionEvent.obtain(ev); + event.setLocation(x, y); + renderView.onTouch(event); + event.recycle(); + return true; + } + + @Override + public int getAdditionalTop() { + return AndroidUtilities.dp(48); + } + + @Override + public int getAdditionalBottom() { + return AndroidUtilities.dp(24); + } + + @Override + public RenderView getRenderView() { + return renderView; + } + + @Override + public void setTransform(float scale, float trX, float trY, float imageWidth, float imageHeight) { + this.scale = scale; + this.imageWidth = imageWidth; + this.imageHeight = imageHeight; + inputTransformX = trX; + inputTransformY = trY; + transformX = trX; + trY += panTranslationY; + transformY = trY; + for (int a = 0; a < 4; a++) { + View view; + float additionlScale = 1.0f; + if (a == 0) { + view = entitiesView; + } else if (a == 1) { + view = selectionContainerView; + } else if (a == 2) { + view = renderView; + } else { + view = renderInputView; + } + float tx; + float ty; + float rotation = 0; + if (currentCropState != null) { + additionlScale *= currentCropState.cropScale; + + int w = view.getMeasuredWidth(); + int h = view.getMeasuredHeight(); + if (w == 0 || h == 0) { + return; + } + int tr = currentCropState.transformRotation; + int fw = w, rotatedW = w; + int fh = h, rotatedH = h; + if (tr == 90 || tr == 270) { + int temp = fw; + fw = rotatedW = fh; + fh = rotatedH = temp; + } + fw *= currentCropState.cropPw; + fh *= currentCropState.cropPh; + + float sc = Math.max(imageWidth / fw, imageHeight / fh); + additionlScale *= sc; + + tx = trX + currentCropState.cropPx * rotatedW * scale * sc * currentCropState.cropScale; + ty = trY + currentCropState.cropPy * rotatedH * scale * sc * currentCropState.cropScale; + rotation = currentCropState.cropRotate + tr; + } else { + if (a == 0) { + additionlScale *= baseScale; + } + tx = trX; + ty = trY; + } + float finalScale = scale * additionlScale; + if (Float.isNaN(finalScale)) { + finalScale = 1f; + } + view.setScaleX(finalScale); + view.setScaleY(finalScale); + view.setTranslationX(tx); + view.setTranslationY(ty); + view.setRotation(rotation); + view.invalidate(); + } + invalidate(); + } + + @Override + public List getMasks() { + ArrayList result = null; + int count = entitiesView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = entitiesView.getChildAt(a); + if (child instanceof StickerView) { + TLRPC.Document document = ((StickerView) child).getSticker(); + if (result == null) { + result = new ArrayList<>(); + } + TLRPC.TL_inputDocument inputDocument = new TLRPC.TL_inputDocument(); + inputDocument.id = document.id; + inputDocument.access_hash = document.access_hash; + inputDocument.file_reference = document.file_reference; + if (inputDocument.file_reference == null) { + inputDocument.file_reference = new byte[0]; + } + result.add(inputDocument); + } else if (child instanceof TextPaintView) { + TextPaintView textPaintView = (TextPaintView) child; + CharSequence text = textPaintView.getText(); + if (text instanceof Spanned) { + AnimatedEmojiSpan[] spans = ((Spanned) text).getSpans(0, text.length(), AnimatedEmojiSpan.class); + if (spans != null) { + for (int i = 0; i < spans.length; ++i) { + AnimatedEmojiSpan span = spans[i]; + if (span != null) { + TLRPC.Document document; + if (span.document != null) { + document = span.document; + } else { + document = AnimatedEmojiDrawable.findDocument(currentAccount, span.getDocumentId()); + } + + if (document != null) { + if (result == null) { + result = new ArrayList<>(); + } + TLRPC.TL_inputDocument inputDocument = new TLRPC.TL_inputDocument(); + inputDocument.id = document.id; + inputDocument.access_hash = document.access_hash; + inputDocument.file_reference = document.file_reference; + if (inputDocument.file_reference == null) { + inputDocument.file_reference = new byte[0]; + } + result.add(inputDocument); + } + } + } + } + } + } + } + return result; + } + + @Override + public void onBrushSelected(Brush brush) { + if (brush instanceof Brush.Blurer || brush instanceof Brush.Eraser) { + weightChooserView.setMinMax(0.4f, 1.75f); + } else { + weightChooserView.setMinMax(0.05f, 1f); + } + weightChooserView.setDrawCenter(!(brush instanceof Brush.Shape)); + if (renderView.getCurrentBrush() instanceof Brush.Shape) { + ignoreToolChangeAnimationOnce = true; + } + renderView.setBrush(brush); + colorSwatch.brushWeight = weightDefaultValueOverride.get(); + setCurrentSwatch(colorSwatch, true); + renderInputView.invalidate(); + } + + @Override + public void onTypefaceButtonClicked() { + showTypefaceMenu(true); + } + + private void showTypefaceMenu(boolean show) { + if (isTypefaceMenuShown != show) { + isTypefaceMenuShown = show; + + if (typefaceMenuTransformAnimation != null) { + typefaceMenuTransformAnimation.cancel(); + } + + typefaceMenuTransformAnimation = new SpringAnimation(new FloatValueHolder(show ? 0 : 1000f)); + typefaceMenuTransformAnimation.setSpring(new SpringForce() + .setFinalPosition(show ? 1000f : 0f) + .setStiffness(1250f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); + + if (show) { + typefaceListView.setAlpha(0f); + typefaceListView.setVisibility(VISIBLE); + } + + typefaceMenuTransformAnimation.addUpdateListener((animation, value, velocity) -> { + typefaceMenuTransformProgress = value / 1000f; + typefaceListView.setAlpha(typefaceMenuTransformProgress); + typefaceListView.invalidate(); + overlayLayout.invalidate(); + + textOptionsView.getTypefaceCell().setAlpha(1f - typefaceMenuTransformProgress); + }); + typefaceMenuTransformAnimation.addEndListener((animation, canceled, value, velocity) -> { + if (animation == typefaceMenuTransformAnimation) { + typefaceMenuTransformAnimation = null; + + if (!show) { + typefaceListView.setVisibility(GONE); + } + typefaceListView.setMaskProvider(null); + } + }); + typefaceMenuTransformAnimation.start(); + } + } + + @SuppressLint("NotifyDataSetChanged") + private void showColorList(boolean show) { + if (isColorListShown != show) { + isColorListShown = show; + + if (toolsTransformAnimation != null) { + toolsTransformAnimation.cancel(); + } + + toolsTransformAnimation = new SpringAnimation(new FloatValueHolder(show ? 0 : 1000f)); + toolsTransformAnimation.setSpring(new SpringForce() + .setFinalPosition(show ? 1000f : 0f) + .setStiffness(1250f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); + + boolean[] moveBottomLayout = new boolean[] { keyboardVisible || emojiViewVisible }; + float bottomLayoutTranslationY = bottomLayout.getTranslationY(); + + View barView = getBarView(); + toolsTransformAnimation.addUpdateListener((animation, value, velocity) -> { + toolsTransformProgress = value / 1000f; + + float scale = 0.6f + 0.4f * (1f - toolsTransformProgress); + barView.setScaleX(scale); + barView.setScaleY(scale); + barView.setTranslationY(AndroidUtilities.dp(16) * Math.min(toolsTransformProgress, 0.25f) / 0.25f); + barView.setAlpha(1f - Math.min(toolsTransformProgress, 0.25f) / 0.25f); + + colorsListView.setProgress(toolsTransformProgress, show); + + doneButton.setProgress(toolsTransformProgress); + cancelButton.setProgress(toolsTransformProgress); + + tabsLayout.setTranslationY(AndroidUtilities.dp(32) * toolsTransformProgress); + if (adjustPanLayoutHelper.animationInProgress()) { + moveBottomLayout[0] = false; + } + if (moveBottomLayout[0]) { + float progress = show ? toolsTransformProgress : 1f - toolsTransformProgress; + bottomLayout.setTranslationY(bottomLayoutTranslationY - AndroidUtilities.dp(40) * progress * (show ? 1 : -1)); + } + bottomLayout.invalidate(); + + if (barView == textOptionsView) { + overlayLayout.invalidate(); + } + }); + toolsTransformAnimation.addEndListener((animation, canceled, value, velocity) -> { + if (animation == toolsTransformAnimation) { + toolsTransformAnimation = null; + + if (!show) { + colorsListView.setVisibility(GONE); + PersistColorPalette.getInstance(currentAccount).saveColors(); + colorsListView.getAdapter().notifyDataSetChanged(); + } + } + }); + toolsTransformAnimation.start(); + + if (show) { + colorsListView.setVisibility(VISIBLE); + colorsListView.setSelectedColorIndex(0); + } + } + } + + private void setCurrentSwatch(Swatch swatch, boolean updateInterface) { + if (colorSwatch != swatch) { + colorSwatch.color = swatch.color; + colorSwatch.colorLocation = swatch.colorLocation; + colorSwatch.brushWeight = swatch.brushWeight; + + PersistColorPalette.getInstance(currentAccount).selectColor(swatch.color); + PersistColorPalette.getInstance(currentAccount).setCurrentWeight(swatch.brushWeight); + } + + renderView.setColor(swatch.color); + renderView.setBrushSize(swatch.brushWeight); + + if (updateInterface) { + if (bottomLayout != null) { + bottomLayout.invalidate(); + } + } + + if (currentEntityView instanceof TextPaintView) { + ((TextPaintView) currentEntityView).setSwatch(new Swatch(swatch.color, swatch.colorLocation, swatch.brushWeight)); + } + } + + @Override + public void onBackPressed() { + } + + @Override + public void onColorPickerSelected() { + showColorList(true); + } + + @Override + public void onTextOutlineSelected(View v) { + int[] loc = new int[2]; + v.getLocationInWindow(loc); + + showPopup(() -> { + for (int a = 0; a < 3; a++) { + String text; + int icon; + if (a == 0) { + text = LocaleController.getString("PaintOutlined", R.string.PaintOutlined); + icon = R.drawable.msg_text_outlined; + } else if (a == 1) { + text = LocaleController.getString("PaintRegular", R.string.PaintRegular); + icon = R.drawable.msg_text_regular; + } else { + text = LocaleController.getString("PaintFramed", R.string.PaintFramed); + icon = R.drawable.msg_text_framed; + } + int finalA = a; + popupLayout.addView(buttonForPopup(text, icon, selectedTextType == a, ()->setTextType(finalA)), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + } + }, this, Gravity.LEFT | Gravity.TOP, 0, getHeight() - emojiPadding); + } + + private PopupButton buttonForPopup(String text, int icon, boolean selected, Runnable onClick) { + PopupButton button = new PopupButton(getContext()); + button.setIcon(icon); + button.setText(text); + button.setSelected(selected); + if (onClick != null) { + button.setOnClickListener(e -> onClick.run()); + } + return button; + } + + public class PopupButton extends LinearLayout { + + public TextView textView; + FrameLayout imagesView; + ImageView imageView; + ImageView image2View; + + float imageSwitchT; + boolean imageSwitchFill; + ValueAnimator imageSwitchAnimator; + + ImageView checkView; + + public PopupButton(Context context) { + super(context); + setOrientation(LinearLayout.HORIZONTAL); + setBackground(Theme.getSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), false)); + + imagesView = new FrameLayout(context) { + Path path = new Path(); + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (imageSwitchAnimator != null) { + if (imageSwitchFill && child == image2View || !imageSwitchFill && child == imageView) { + float r = (imageSwitchFill ? imageSwitchT : 1f - imageSwitchT) * getMeasuredWidth() / 2f; + canvas.save(); + path.rewind(); + path.addCircle(getMeasuredWidth() / 2f, getMeasuredHeight() / 2f, r, Path.Direction.CW); + canvas.clipPath(path); + boolean res = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return res; + } + } + return super.drawChild(canvas, child, drawingTime); + } + }; + + addView(imagesView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 16, 0, 16, 0)); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setColorFilter(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + imagesView.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + image2View = new ImageView(context); + image2View.setScaleType(ImageView.ScaleType.CENTER); + image2View.setColorFilter(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + image2View.setVisibility(View.GONE); + imagesView.addView(image2View, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + + textView = new TextView(context); + textView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 0, 0, 16, 0)); + + checkView = new ImageView(context); + checkView.setImageResource(R.drawable.msg_text_check); + checkView.setScaleType(ImageView.ScaleType.CENTER); + checkView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_radioBackgroundChecked), PorterDuff.Mode.MULTIPLY)); + checkView.setVisibility(View.GONE); + addView(checkView, LayoutHelper.createLinear(50, LayoutHelper.MATCH_PARENT)); + } + + public void setSelected(boolean selected) { + checkView.setVisibility(selected ? View.VISIBLE : View.GONE); + } + + public void setText(CharSequence text) { + textView.setText(text); + } + + public void setIcon(int resId) { + setIcon(resId, true,false); + } + + public void setIcon(int resId, boolean fillup, boolean animated) { + if (animated) { + if (imageSwitchAnimator != null) { + imageSwitchAnimator.cancel(); + imageSwitchAnimator = null; + setIcon(resId, false, false); + return; + } + imageSwitchFill = fillup; + image2View.setImageResource(resId); + image2View.setVisibility(View.VISIBLE); + image2View.setAlpha(1f); + imageSwitchAnimator = ValueAnimator.ofFloat(0, 1); + imageSwitchAnimator.addUpdateListener(anm -> { + imageSwitchT = (float) anm.getAnimatedValue(); + if (!fillup) { + imageView.setAlpha(1f - imageSwitchT); + } + imagesView.invalidate(); + }); + imageSwitchAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + ImageView buff = imageView; + imageView = image2View; + image2View = buff; + image2View.bringToFront(); + image2View.setVisibility(View.GONE); + imageSwitchAnimator = null; + } + }); + imageSwitchAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + imageSwitchAnimator.setDuration(420); + imageSwitchAnimator.start(); + } else { + imageView.setImageResource(resId); + } + } + + @Override + public boolean performClick() { + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + return super.performClick(); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return true; + } + } + + private void setTextType(int type) { + selectedTextType = type; + if (currentEntityView instanceof TextPaintView) { + if (type == 0 && colorSwatch.color == Color.WHITE) { + setNewColor(Color.BLACK); + } else if ((type == 1 || type == 2) && colorSwatch.color == Color.BLACK) { + setNewColor(Color.WHITE); + } + ((TextPaintView) currentEntityView).setType(type); + } + PersistColorPalette.getInstance(currentAccount).setCurrentTextType(type); + textOptionsView.setOutlineType(type); + } + + @Override + public void onNewTextSelected() { + if (keyboardVisible || emojiViewVisible) { + onEmojiButtonClick(); + } else { + createText(true); + } + } + + @Override + public void onTypefaceSelected(PaintTypeface typeface) { + PersistColorPalette.getInstance(currentAccount).setCurrentTypeface(typeface.getKey()); + if (currentEntityView instanceof TextPaintView) { + ((TextPaintView) currentEntityView).setTypeface(typeface); + } + } + + @Override + public void onTextAlignmentSelected(int align) { + if (currentEntityView instanceof TextPaintView) { + setTextAlignment((TextPaintView) currentEntityView, align); + PersistColorPalette.getInstance(currentAccount).setCurrentAlignment(align); + } + } + + private void setTextAlignment(TextPaintView textPaintView, int align) { + textPaintView.setAlign(align); + + int gravity; + switch (align) { + default: + case PaintTextOptionsView.ALIGN_LEFT: + gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; + break; + case PaintTextOptionsView.ALIGN_CENTER: + gravity = Gravity.CENTER; + break; + case PaintTextOptionsView.ALIGN_RIGHT: + gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; + break; + } + + textPaintView.getEditText().setGravity(gravity); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + int textAlign; + switch (align) { + default: + case PaintTextOptionsView.ALIGN_LEFT: + textAlign = LocaleController.isRTL ? TEXT_ALIGNMENT_TEXT_END : TEXT_ALIGNMENT_TEXT_START; + break; + case PaintTextOptionsView.ALIGN_CENTER: + textAlign = TEXT_ALIGNMENT_CENTER; + break; + case PaintTextOptionsView.ALIGN_RIGHT: + textAlign = LocaleController.isRTL ? TEXT_ALIGNMENT_TEXT_START : TEXT_ALIGNMENT_TEXT_END; + break; + } + textPaintView.getEditText().setTextAlignment(textAlign); + } + } + + @Override + public void onAddButtonPressed(View btn) { + showPopup(() -> { + boolean fill = PersistColorPalette.getInstance(currentAccount).getFillShapes(); + for (int a = 0; a < Brush.Shape.SHAPES_LIST.size(); a++) { + final Brush.Shape shape = Brush.Shape.SHAPES_LIST.get(a); + int icon = fill ? shape.getFilledIconRes() : shape.getIconRes(); + PopupButton button = buttonForPopup(shape.getShapeName(), icon, false, () -> { + if (renderView.getCurrentBrush() instanceof Brush.Shape) { + ignoreToolChangeAnimationOnce = true; + } + onBrushSelected(shape); + paintToolsView.animatePlusToIcon(icon); + }); + button.setOnLongClickListener(e -> { + if (popupLayout != null) { + PersistColorPalette.getInstance(currentAccount).toggleFillShapes(); + boolean newfill = PersistColorPalette.getInstance(currentAccount).getFillShapes(); + for (int i = 0; i < popupLayout.getItemsCount(); ++i) { + View child = popupLayout.getItemAt(i); + if (child instanceof PopupButton) { + final Brush.Shape thisshape = Brush.Shape.SHAPES_LIST.get(i); + int thisicon = newfill ? thisshape.getFilledIconRes() : thisshape.getIconRes(); + ((PopupButton) child).setIcon(thisicon, newfill, true); + } + } + } + return true; + }); + popupLayout.addView(button, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + } + }, this, Gravity.RIGHT | Gravity.TOP, 0, getHeight()); + } + + private void showMenuForEntity(final EntityView entityView) { + int[] pos = getCenterLocationInWindow(entityView); + int x = pos[0]; + int y = pos[1] - AndroidUtilities.dp(32); + + showPopup(() -> { + LinearLayout parent = new LinearLayout(getContext()); + parent.setOrientation(LinearLayout.HORIZONTAL); + + TextView deleteView = new TextView(getContext()); + deleteView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + deleteView.setBackground(Theme.getSelectorDrawable(false)); + deleteView.setGravity(Gravity.CENTER_VERTICAL); + deleteView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(14), 0); + deleteView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + deleteView.setTag(0); + deleteView.setText(LocaleController.getString("PaintDelete", R.string.PaintDelete)); + deleteView.setOnClickListener(v -> { + removeEntity(entityView); + + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + }); + parent.addView(deleteView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + + if (entityView instanceof TextPaintView) { + TextView editView = new TextView(getContext()); + editView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + editView.setBackground(Theme.getSelectorDrawable(false)); + editView.setGravity(Gravity.CENTER_VERTICAL); + editView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); + editView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + editView.setTag(1); + editView.setText(LocaleController.getString("PaintEdit", R.string.PaintEdit)); + editView.setOnClickListener(v -> { + editSelectedTextEntity(); + + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + }); + parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + } + + TextView duplicateView = new TextView(getContext()); + duplicateView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + duplicateView.setBackgroundDrawable(Theme.getSelectorDrawable(false)); + duplicateView.setGravity(Gravity.CENTER_VERTICAL); + duplicateView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(16), 0); + duplicateView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + duplicateView.setTag(2); + duplicateView.setText(LocaleController.getString("PaintDuplicate", R.string.PaintDuplicate)); + duplicateView.setOnClickListener(v -> { + duplicateSelectedEntity(); + + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + }); + parent.addView(duplicateView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + + popupLayout.addView(parent); + + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) parent.getLayoutParams(); + params.width = LayoutHelper.WRAP_CONTENT; + params.height = LayoutHelper.WRAP_CONTENT; + parent.setLayoutParams(params); + }, this, Gravity.LEFT | Gravity.TOP, x, y); + } + + private void duplicateSelectedEntity() { + if (currentEntityView == null) { + return; + } + + EntityView entityView = null; + Point position = startPositionRelativeToEntity(currentEntityView); + + if (currentEntityView instanceof StickerView) { + StickerView newStickerView = new StickerView(getContext(), (StickerView) currentEntityView, position); + newStickerView.setDelegate(this); + entitiesView.addView(newStickerView); + entityView = newStickerView; + } else if (currentEntityView instanceof TextPaintView) { + TextPaintView newTextPaintView = new TextPaintView(getContext(), (TextPaintView) currentEntityView, position); + newTextPaintView.setDelegate(this); + newTextPaintView.setMaxWidth((int) (getPaintingSize().width - 20)); + entitiesView.addView(newTextPaintView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + entityView = newTextPaintView; + } + + registerRemovalUndo(entityView); + selectEntity(entityView); + } + + private Point startPositionRelativeToEntity(EntityView entityView) { + float offset = 200.0f; + if (currentCropState != null) { + offset /= currentCropState.cropScale; + } + + if (entityView != null) { + Point position = entityView.getPosition(); + return new Point(position.x + offset, position.y + offset); + } else { + float minimalDistance = 100.0f; + if (currentCropState != null) { + minimalDistance /= currentCropState.cropScale; + } + Point position = centerPositionForEntity(); + while (true) { + boolean occupied = false; + for (int index = 0; index < entitiesView.getChildCount(); index++) { + View view = entitiesView.getChildAt(index); + if (!(view instanceof EntityView)) + continue; + + Point location = ((EntityView) view).getPosition(); + float distance = (float) Math.sqrt(Math.pow(location.x - position.x, 2) + Math.pow(location.y - position.y, 2)); + if (distance < minimalDistance) { + occupied = true; + } + } + + if (!occupied) { + break; + } else { + position = new Point(position.x + offset, position.y + offset); + } + } + return position; + } + } + + private void showPopup(Runnable setupRunnable, View parent, int gravity, int x, int y) { + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(); + return; + } + + if (popupLayout == null) { + popupRect = new android.graphics.Rect(); + popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), resourcesProvider); + popupLayout.setAnimationEnabled(true); + popupLayout.setBackgroundColor(-14145495); + popupLayout.setOnTouchListener((v, event) -> { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + if (popupWindow != null && popupWindow.isShowing()) { + v.getHitRect(popupRect); + if (!popupRect.contains((int) event.getX(), (int) event.getY())) { + popupWindow.dismiss(); + } + } + } + return false; + }); + popupLayout.setDispatchKeyEventListener(keyEvent -> { + if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && keyEvent.getRepeatCount() == 0 && popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(); + } + }); + popupLayout.setShownFromBottom(true); + } + + popupLayout.removeInnerViews(); + setupRunnable.run(); + + if (popupWindow == null) { + popupWindow = new ActionBarPopupWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + popupWindow.setAnimationEnabled(true); + popupWindow.setAnimationStyle(R.style.PopupAnimation); + popupWindow.setOutsideTouchable(true); + popupWindow.setClippingEnabled(true); + popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); + popupWindow.getContentView().setFocusableInTouchMode(true); + popupWindow.setOnDismissListener(() -> popupLayout.removeInnerViews()); + } + + popupLayout.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST)); + + popupWindow.setFocusable(true); + + if ((gravity & Gravity.TOP) != 0) { + x -= popupLayout.getMeasuredWidth() / 2; + y -= popupLayout.getMeasuredHeight(); + } + popupWindow.showAtLocation(parent, gravity, x, y); + popupWindow.startAnimation(popupLayout); + } + + private int getThemedColor(String key) { + Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null; + return color != null ? color : Theme.getColor(key); + } + + @Override + public PersistColorPalette onGetPalette() { + return PersistColorPalette.getInstance(currentAccount); + } + + private Size baseStickerSize() { + float side = (float) Math.floor(getPaintingSize().width * 0.5); + return new Size(side, side); + } + + private Point centerPositionForEntity() { + Size paintingSize = getPaintingSize(); + float x = paintingSize.width / 2.0f; + float y = paintingSize.height / 2.0f; + if (currentCropState != null) { + float rotation = (float) Math.toRadians(-(currentCropState.transformRotation + currentCropState.cropRotate)); + float px = (float) (currentCropState.cropPx * Math.cos(rotation) - currentCropState.cropPy * Math.sin(rotation)); + float py = (float) (currentCropState.cropPx * Math.sin(rotation) + currentCropState.cropPy * Math.cos(rotation)); + x -= px * paintingSize.width; + y -= py * paintingSize.height; + } + return new Point(x, y); + } + + private StickerPosition calculateStickerPosition(TLRPC.Document document) { + TLRPC.TL_maskCoords maskCoords = null; + + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeSticker) { + maskCoords = attribute.mask_coords; + break; + } + } + + float rotation; + float baseScale; + if (currentCropState != null) { + rotation = -(currentCropState.transformRotation + currentCropState.cropRotate); + baseScale = 0.75f / currentCropState.cropScale; + } else { + rotation = 0.0f; + baseScale = 0.75f; + } + StickerPosition defaultPosition = new StickerPosition(centerPositionForEntity(), baseScale, rotation); + // NekoX: Remove face detection parts + return defaultPosition; + } + +// private PhotoFace getRandomFaceWithVacantAnchor(int anchor, long documentId, TLRPC.TL_maskCoords maskCoords) { +// if (anchor < 0 || anchor > 3 || faces.isEmpty()) { +// return null; +// } +// +// int count = faces.size(); +// int randomIndex = Utilities.random.nextInt(count); +// int remaining = count; +// +// PhotoFace selectedFace = null; +// for (int i = randomIndex; remaining > 0; i = (i + 1) % count, remaining--) { +// PhotoFace face = faces.get(i); +// if (!isFaceAnchorOccupied(face, anchor, documentId, maskCoords)) { +// return face; +// } +// } +// +// return selectedFace; +// } + +// private boolean isFaceAnchorOccupied(PhotoFace face, int anchor, long documentId, TLRPC.TL_maskCoords maskCoords) { +// Point anchorPoint = face.getPointForAnchor(anchor); +// if (anchorPoint == null) { +// return true; +// } +// +// float minDistance = face.getWidthForAnchor(0) * 1.1f; +// +// for (int index = 0; index < entitiesView.getChildCount(); index++) { +// View view = entitiesView.getChildAt(index); +// if (!(view instanceof StickerView)) { +// continue; +// } +// +// StickerView stickerView = (StickerView) view; +// if (stickerView.getAnchor() != anchor) { +// continue; +// } +// +// Point location = stickerView.getPosition(); +// float distance = (float)Math.hypot(location.x - anchorPoint.x, location.y - anchorPoint.y); +// if ((documentId == stickerView.getSticker().id || faces.size() > 1) && distance < minDistance) { +// return true; +// } +// } +// +// return false; +// } + + private StickerView createSticker(Object parentObject, TLRPC.Document sticker, boolean select) { + StickerPosition position = calculateStickerPosition(sticker); + StickerView view = new StickerView(getContext(), position.position, position.angle, position.scale, baseStickerSize(), sticker, parentObject) { + @Override + protected void didSetAnimatedSticker(RLottieDrawable drawable) { + LPhotoPaintView.this.didSetAnimatedSticker(drawable); + } + }; + if (position.position.x == entitiesView.getMeasuredWidth() / 2f) { + view.setHasStickyX(true); + } + if (position.position.y == entitiesView.getMeasuredHeight() / 2f) { + view.setHasStickyY(true); + } + view.setDelegate(this); + entitiesView.addView(view); + if (select) { + registerRemovalUndo(view); + selectEntity(view); + } + return view; + } + + private void removeEntity(EntityView entityView) { + if (entityView == currentEntityView && currentEntityView != null) { + currentEntityView.deselect(); + currentEntityView = null; + + if (entityView instanceof TextPaintView) { + if (tabsSelectionAnimator != null && tabsNewSelectedIndex != 0) { + tabsSelectionAnimator.cancel(); + } + switchTab(0); + } + } + entitiesView.removeView(entityView); + if (entityView != null) { + undoStore.unregisterUndo(entityView.getUUID()); + } + + weightChooserView.setValueOverride(weightDefaultValueOverride); + weightChooserView.setShowPreview(true); + colorSwatch.brushWeight = weightDefaultValueOverride.get(); + setCurrentSwatch(colorSwatch, true); + } + + private void registerRemovalUndo(final EntityView entityView) { + undoStore.registerUndo(entityView.getUUID(), () -> removeEntity(entityView)); + } + + protected void didSetAnimatedSticker(RLottieDrawable drawable) {} + + @Override + public boolean onEntitySelected(EntityView entityView) { + return selectEntity(entityView); + } + + @Override + public boolean onEntityLongClicked(EntityView entityView) { + showMenuForEntity(entityView); + return true; + } + + private float[] temp = new float[2]; + @Override + public float[] getTransformedTouch(float x, float y) { + float x2 = (x - AndroidUtilities.displaySize.x / 2f); + float y2 = (y - AndroidUtilities.displaySize.y / 2f); + float rotation = (float) Math.toRadians(-entitiesView.getRotation()); + temp[0] = (float) (x2 * Math.cos(rotation) - y2 * Math.sin(rotation)) + AndroidUtilities.displaySize.x / 2f; + temp[1] = (float) (x2 * Math.sin(rotation) + y2 * Math.cos(rotation)) + AndroidUtilities.displaySize.y / 2f; + return temp; + } + + @Override + public int[] getCenterLocation(EntityView entityView) { + return getCenterLocationInWindow(entityView); + } + + private int[] pos = new int[2]; + private int[] getCenterLocationInWindow(View view) { + view.getLocationInWindow(pos); + float rotation = (float) Math.toRadians(view.getRotation() + (currentCropState != null ? currentCropState.cropRotate + currentCropState.transformRotation : 0)); + float width = view.getWidth() * view.getScaleX() * entitiesView.getScaleX(); + float height = view.getHeight() * view.getScaleY() * entitiesView.getScaleY(); + float px = (float) (width * Math.cos(rotation) - height * Math.sin(rotation)); + float py = (float) (width * Math.sin(rotation) + height * Math.cos(rotation)); + pos[0] += px / 2; + pos[1] += py / 2; + return pos; + } + + @Override + public boolean allowInteraction(EntityView entityView) { + return !editingText; + } + + @Override + public float getCropRotation() { + return currentCropState != null ? currentCropState.cropRotate + currentCropState.transformRotation : 0; + } + + private static class StickerPosition { + private Point position; + private float scale; + private float angle; + + StickerPosition(Point position, float scale, float angle) { + this.position = position; + this.scale = scale; + this.angle = angle; + } + } + + /* === emoji keyboard support === */ + + private EmojiView emojiView; + private boolean emojiViewVisible, emojiViewWasVisible; + private boolean keyboardVisible, isAnimatePopupClosing; + private int emojiPadding, emojiWasPadding; + private boolean translateBottomPanelAfterResize; + private int keyboardHeight, keyboardHeightLand; + private boolean waitingForKeyboardOpen; + private int lastSizeChangeValue1; + private boolean lastSizeChangeValue2; + private boolean destroyed; + + private Runnable openKeyboardRunnable = new Runnable() { + @Override + public void run() { + if (!(currentEntityView instanceof TextPaintView)) { + return; + } + final EditTextOutline editText = ((TextPaintView) currentEntityView).getEditText(); + if (!destroyed && editText != null && waitingForKeyboardOpen && !keyboardVisible && !AndroidUtilities.usingHardwareInput && !AndroidUtilities.isInMultiwindow && AndroidUtilities.isTablet()) { + editText.requestFocus(); + AndroidUtilities.showKeyboard(editText); + AndroidUtilities.cancelRunOnUIThread(openKeyboardRunnable); + AndroidUtilities.runOnUIThread(openKeyboardRunnable, 100); + } + } + }; + + @Override + public void onEmojiButtonClick() { + boolean emojiViewWasVisible = emojiViewVisible; + if (emojiViewWasVisible && currentEntityView instanceof TextPaintView) { + bottomPanelIgnoreOnce = true; + } + showEmojiPopup(emojiViewVisible ? 0 : 1); + if (emojiViewWasVisible && currentEntityView instanceof TextPaintView) { + final EditTextOutline editText = ((TextPaintView) currentEntityView).getEditText(); + AndroidUtilities.showKeyboard(editText); + } + } + + private void showEmojiPopup(int show) { + final boolean ignore = bottomPanelIgnoreOnce; + bottomPanelIgnoreOnce = false; + if (show == 1) { + boolean emojiWasVisible = emojiView != null && emojiView.getVisibility() == View.VISIBLE; + createEmojiView(); + + emojiView.setVisibility(VISIBLE); + emojiViewWasVisible = emojiViewVisible; + emojiViewVisible = true; + View currentView = emojiView; + + if (keyboardHeight <= 0) { + if (AndroidUtilities.isTablet()) { + keyboardHeight = AndroidUtilities.dp(150); + } else { + keyboardHeight = MessagesController.getGlobalEmojiSettings().getInt("kbd_height", AndroidUtilities.dp(200)); + } + } + if (keyboardHeightLand <= 0) { + if (AndroidUtilities.isTablet()) { + keyboardHeightLand = AndroidUtilities.dp(150); + } else { + keyboardHeightLand = MessagesController.getGlobalEmojiSettings().getInt("kbd_height_land3", AndroidUtilities.dp(200)); + } + } + int currentHeight = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? keyboardHeightLand : keyboardHeight; + + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) currentView.getLayoutParams(); + layoutParams.height = currentHeight; + currentView.setLayoutParams(layoutParams); + if (!AndroidUtilities.isInMultiwindow && !AndroidUtilities.isTablet() && currentEntityView instanceof TextPaintView) { + final EditTextOutline editText = ((TextPaintView) currentEntityView).getEditText(); + AndroidUtilities.hideKeyboard(editText); + } + + emojiPadding = emojiWasPadding = currentHeight; + requestLayout(); + + ChatActivityEnterViewAnimatedIconView emojiButton = textOptionsView.getEmojiButton(); + if (emojiButton != null) { + emojiButton.setState(ChatActivityEnterViewAnimatedIconView.State.KEYBOARD, true); + } + onWindowSizeChanged(); + + if (!emojiWasVisible) { + if (SharedConfig.smoothKeyboard) { + if (keyboardVisible) { + translateBottomPanelAfterResize = true; + weightChooserView.startPanTransition(AndroidUtilities.displaySize.y, AndroidUtilities.displaySize.y - emojiPadding); +// weightChooserView.updatePanTransition(0, 1); +// weightChooserView.stopPanTransition(); + } else { + ValueAnimator animator = ValueAnimator.ofFloat(emojiPadding, 0); + weightChooserView.startPanTransition(AndroidUtilities.displaySize.y, AndroidUtilities.displaySize.y - emojiPadding); + animator.addUpdateListener(animation -> { + float v = (float) animation.getAnimatedValue(); + emojiView.setTranslationY(v); + if (!ignore) { + bottomPanelTranslationY(v, 1f - v / emojiPadding); + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + emojiView.setTranslationY(0); + if (!ignore) { + bottomPanelTranslationY(0, 1); + } + weightChooserView.stopPanTransition(); + } + }); + animator.setDuration(AdjustPanLayoutHelper.keyboardDuration); + animator.setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator); + animator.start(); + } + } + } + } else { + ChatActivityEnterViewAnimatedIconView emojiButton = textOptionsView.getEmojiButton(); + if (emojiButton != null) { + emojiButton.setState(ChatActivityEnterViewAnimatedIconView.State.SMILE, true); + } + if (emojiView != null) { + emojiViewWasVisible = emojiViewVisible; + emojiViewVisible = false; + if (AndroidUtilities.usingHardwareInput || AndroidUtilities.isInMultiwindow) { + emojiView.setVisibility(GONE); + } + } + if (show == 0) { + emojiPadding = 0; + } + bottomPanelTranslationY(0, 0); + weightChooserView.startPanTransition(AndroidUtilities.displaySize.y - emojiPadding, AndroidUtilities.displaySize.y); + weightChooserView.updatePanTransition(0, 1); + weightChooserView.stopPanTransition(); + requestLayout(); + onWindowSizeChanged(); + } + + updatePlusEmojiKeyboardButton(); + } + + private void hideEmojiPopup(boolean byBackButton) { + if (emojiViewVisible) { + showEmojiPopup(0); + } + if (byBackButton) { + if (SharedConfig.smoothKeyboard && emojiView != null && emojiView.getVisibility() == View.VISIBLE && !waitingForKeyboardOpen) { + int height = emojiView.getMeasuredHeight(); + ValueAnimator animator = ValueAnimator.ofFloat(0, height); + final boolean ignore = bottomPanelIgnoreOnce; + bottomPanelIgnoreOnce = false; + weightChooserView.startPanTransition(AndroidUtilities.displaySize.y - height, AndroidUtilities.displaySize.y); + animator.addUpdateListener(animation -> { + float v = (float) animation.getAnimatedValue(); + emojiView.setTranslationY(v); + if (!ignore) { + bottomPanelTranslationY(v - height, 1f - v / height); + } + }); + isAnimatePopupClosing = true; + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + isAnimatePopupClosing = false; + emojiView.setTranslationY(0); + if (!ignore) { + bottomPanelTranslationY(0, 0); + } + weightChooserView.stopPanTransition(); + hideEmojiView(); + } + }); + animator.setDuration(AdjustPanLayoutHelper.keyboardDuration); + animator.setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator); + animator.start(); + } else { + hideEmojiView(); + } + } + } + + private boolean bottomPanelIgnoreOnce; + private void bottomPanelTranslationY(float ty, float progress) { + bottomLayout.setTranslationY(ty - emojiPadding + progress * AndroidUtilities.dp(40)); + panTranslationY = (ty - emojiPadding) / 2f; // (-keyboardHeight / 2f * (panTranslationProgress) + -(emojiPadding + ty) / 2); + panTranslationProgress = 1f + 2f * panTranslationY / keyboardHeight; + weightChooserView.updatePanTransition(emojiViewVisible ? ty : 0, progress); + setTransform(scale, inputTransformX, inputTransformY, imageWidth, imageHeight); + ((View) getParent()).invalidate(); + } + + @Override + public int getEmojiPadding(boolean panned) { + if (translateBottomPanelAfterResize && panned) { + bottomPanelTranslationY(0, 1); + } + if (keyboardVisible && translateBottomPanelAfterResize && !panned) { + return 0; + } + if (adjustPanLayoutHelper.animationInProgress() && !keyboardVisible) + return keyboardHeight; + return emojiPadding; + } + + private void hideEmojiView() { + if (!emojiViewVisible && emojiView != null && emojiView.getVisibility() != GONE) { + emojiView.setVisibility(GONE); + } + emojiPadding = 0; + } + + private void onWindowSizeChanged() { + int size = getHeight(); + if (!keyboardVisible) { + size -= emojiPadding; + } +// onWindowSizeChanged(size); + } + + @Override + public void onSizeChanged(int height, boolean isWidthGreater) { + if (height > AndroidUtilities.dp(50) && keyboardVisible && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isTablet()) { + if (isWidthGreater) { + keyboardHeightLand = height; + MessagesController.getGlobalEmojiSettings().edit().putInt("kbd_height_land3", keyboardHeightLand).commit(); + } else { + keyboardHeight = height; + MessagesController.getGlobalEmojiSettings().edit().putInt("kbd_height", keyboardHeight).commit(); + } + } + + if (emojiViewVisible) { + int newHeight = isWidthGreater ? keyboardHeightLand : keyboardHeight; + + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) emojiView.getLayoutParams(); + if (layoutParams.width != AndroidUtilities.displaySize.x || layoutParams.height != newHeight) { + layoutParams.width = AndroidUtilities.displaySize.x; + layoutParams.height = newHeight; + emojiView.setLayoutParams(layoutParams); + + emojiPadding = emojiWasPadding = layoutParams.height; + requestLayout(); + onWindowSizeChanged(); + } + } + + if (lastSizeChangeValue1 == height && lastSizeChangeValue2 == isWidthGreater) { + onWindowSizeChanged(); + return; + } + lastSizeChangeValue1 = height; + lastSizeChangeValue2 = isWidthGreater; + + boolean oldValue = keyboardVisible; + if (currentEntityView instanceof TextPaintView) { + final EditTextOutline editText = ((TextPaintView) currentEntityView).getEditText(); + keyboardVisible = editText.isFocused() && height > 0; + } else { + keyboardVisible = false; + } + if (keyboardVisible && emojiViewVisible) { + showEmojiPopup(0); + } + if (emojiPadding != 0 && !keyboardVisible && keyboardVisible != oldValue && !emojiViewVisible) { + emojiPadding = 0; + requestLayout(); + } + if (oldValue && !keyboardVisible && emojiPadding > 0 && translateBottomPanelAfterResize) { + translateBottomPanelAfterResize = false; + bottomPanelTranslationY(0, 1); + weightChooserView.stopPanTransition(); + } + if (keyboardVisible && waitingForKeyboardOpen) { + waitingForKeyboardOpen = false; + AndroidUtilities.cancelRunOnUIThread(openKeyboardRunnable); + } + onWindowSizeChanged(); + + updatePlusEmojiKeyboardButton(); + } + + private void updatePlusEmojiKeyboardButton() { + if (textOptionsView != null) { + if (keyboardVisible) { + textOptionsView.animatePlusToIcon(R.drawable.input_smile); + } else if (emojiViewVisible) { + textOptionsView.animatePlusToIcon(R.drawable.input_keyboard); + } else { + textOptionsView.animatePlusToIcon(R.drawable.msg_add); + } + } + + AndroidUtilities.updateViewShow(undoAllButton, !(keyboardVisible || emojiViewVisible), false, 1, true, null); + AndroidUtilities.updateViewShow(undoButton, !(keyboardVisible || emojiViewVisible), false, 1, true, null); + + AndroidUtilities.updateViewShow(doneTextButton, keyboardVisible || emojiViewVisible, false, 1, true, null); + AndroidUtilities.updateViewShow(cancelTextButton, keyboardVisible || emojiViewVisible, false, 1, true, null); + } + + protected void createEmojiView() { + if (emojiView != null && emojiView.currentAccount != UserConfig.selectedAccount) { + removeView(emojiView); + emojiView = null; + } + if (emojiView != null) { + return; + } + emojiView = new EmojiView(null, true, false, false, getContext(), false, null, null, resourcesProvider); + emojiView.allowEmojisForNonPremium(true); + emojiView.setVisibility(GONE); + if (AndroidUtilities.isTablet()) { + emojiView.setForseMultiwindowLayout(true); + } + emojiView.setDelegate(new EmojiView.EmojiViewDelegate() { + int innerTextChange; + + @Override + public boolean onBackspace() { + final EditTextOutline editText = ((TextPaintView) currentEntityView).getEditText(); + if (editText == null || editText.length() == 0) { + return false; + } + editText.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); + return true; + } + + @Override + public void onAnimatedEmojiUnlockClick() { +// BaseFragment fragment = parentFragment; +// if (fragment == null) { +// fragment = new BaseFragment() { +// @Override +// public int getCurrentAccount() { +// return currentAccount; +// } +// +// @Override +// public Context getContext() { +// return EditTextEmoji.this.getContext(); +// } +// +// @Override +// public Activity getParentActivity() { +// Context context = getContext(); +// while (context instanceof ContextWrapper) { +// if (context instanceof Activity) { +// return (Activity) context; +// } +// context = ((ContextWrapper) context).getBaseContext(); +// } +// return null; +// } +// +// @Override +// public Dialog getVisibleDialog() { +// return new Dialog(getContext()) { +// @Override +// public void dismiss() { +// hidePopup(false); +// closeParent(); +// } +// }; +// } +// }; +// new PremiumFeatureBottomSheet(fragment, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI, false).show(); +// } else { +// fragment.showDialog(new PremiumFeatureBottomSheet(fragment, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI, false)); +// } + } + + @Override + public void onEmojiSelected(String symbol) { + if (!(currentEntityView instanceof TextPaintView)) { + return; + } + TextPaintView textPaintView = (TextPaintView) currentEntityView; + final EditTextOutline editText = textPaintView.getEditText(); + if (editText == null) { + return; + } + int i = editText.getSelectionEnd(); + if (i < 0) { + i = 0; + } + try { + innerTextChange = 2; + CharSequence localCharSequence = Emoji.replaceEmoji(symbol, textPaintView.getFontMetricsInt(), (int) (textPaintView.getFontSize() * .8f), false); + editText.setText(editText.getText().insert(i, localCharSequence)); + int j = i + localCharSequence.length(); + editText.setSelection(j, j); + } catch (Exception e) { + FileLog.e(e); + } finally { + innerTextChange = 0; + } + } + + @Override + public void onCustomEmojiSelected(long documentId, TLRPC.Document document, String emoticon, boolean isRecent) { + final EditTextOutline editText = ((TextPaintView) currentEntityView).getEditText(); + if (editText == null) { + return; + } + int i = editText.getSelectionEnd(); + if (i < 0) { + i = 0; + } + try { + innerTextChange = 2; + SpannableString spannable = new SpannableString(emoticon); + AnimatedEmojiSpan span; + if (document != null) { + span = new AnimatedEmojiSpan(document, editText.getPaint().getFontMetricsInt()); + } else { + span = new AnimatedEmojiSpan(documentId, editText.getPaint().getFontMetricsInt()); + } + spannable.setSpan(span, 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + editText.setText(editText.getText().insert(i, spannable)); + int j = i + spannable.length(); + editText.setSelection(j, j); + } catch (Exception e) { + FileLog.e(e); + } finally { + innerTextChange = 0; + } + } + + @Override + public void onClearEmojiRecent() { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), resourcesProvider); + builder.setTitle(LocaleController.getString("ClearRecentEmojiTitle", R.string.ClearRecentEmojiTitle)); + builder.setMessage(LocaleController.getString("ClearRecentEmojiText", R.string.ClearRecentEmojiText)); + builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton), (dialogInterface, i) -> emojiView.clearRecentEmoji()); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.show(); + } + }); + addView(emojiView); + } + + AdjustPanLayoutHelper adjustPanLayoutHelper = new AdjustPanLayoutHelper(this, false) { + @Override + protected void onTransitionStart(boolean keyboardVisible, int previousHeight, int contentHeight) { + super.onTransitionStart(keyboardVisible, contentHeight); + weightChooserView.startPanTransition(previousHeight, contentHeight); + + if (isColorListShown) { + showColorList(false); + } + } + + @Override + protected void onTransitionEnd() { + panTranslationY = 0; + emojiViewWasVisible = false; + setTransform(scale, inputTransformX, inputTransformY, imageWidth, imageHeight); + super.onTransitionEnd(); + weightChooserView.stopPanTransition(); + } + + @Override + protected void onPanTranslationUpdate(float y, float progress, boolean keyboardVisible) { + topLayout.setTranslationY(y); + panTranslationProgress = 1f - progress; + panTranslationY = y / 2; + bottomLayout.setTranslationY(AndroidUtilities.dp(40) * progress); + weightChooserView.updatePanTransition(y, progress); + setTransform(scale, inputTransformX, inputTransformY, imageWidth, imageHeight); + super.onPanTranslationUpdate(y, progress, keyboardVisible); + ((View) getParent()).invalidate(); + } + + @Override + protected boolean heightAnimationEnabled() { + return !destroyed && !emojiViewVisible; + } + }; + + @Override + public float adjustPanLayoutHelperProgress() { + return panTranslationProgress; + } + + @Override + protected void onAttachedToWindow() { + destroyed = false; + super.onAttachedToWindow(); + adjustPanLayoutHelper.setResizableView(this); + adjustPanLayoutHelper.onAttach(); + } + + @Override + protected void onDetachedFromWindow() { + destroyed = true; + super.onDetachedFromWindow(); + adjustPanLayoutHelper.onDetach(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 712bba0f2..6ef649670 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -208,6 +208,7 @@ import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.NumberPicker; import org.telegram.ui.Components.OtherDocumentPlaceholderDrawable; +import org.telegram.ui.Components.Paint.Views.LPhotoPaintView; import org.telegram.ui.Components.PaintingOverlay; import org.telegram.ui.Components.PhotoCropView; import org.telegram.ui.Components.PhotoFilterView; @@ -391,7 +392,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private MediaController.CropState leftCropState; private MediaController.CropState rightCropState; private PhotoFilterView photoFilterView; - private PhotoPaintView photoPaintView; + private LPhotoPaintView photoPaintView; private AlertDialog visibleDialog; private CaptionTextViewSwitcher captionTextViewSwitcher; private CaptionScrollView captionScrollView; @@ -10365,7 +10366,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { state = editState.cropState; } - photoPaintView = new PhotoPaintView(parentActivity, bitmap, isCurrentVideo ? null : centerImage.getBitmap(), centerImage.getOrientation(), editState.mediaEntities, state, () -> paintingOverlay.hideBitmap(), resourcesProvider) { + photoPaintView = new LPhotoPaintView(parentActivity, currentAccount, bitmap, isCurrentVideo ? null : centerImage.getBitmap(), centerImage.getOrientation(), editState.mediaEntities, state, () -> paintingOverlay.hideBitmap(), resourcesProvider) { @Override protected void onOpenCloseStickersAlert(boolean open) { if (videoPlayer == null) { @@ -10391,7 +10392,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override protected void onTextAdd() { if (!windowView.isFocusable()) { - makeFocusable(); +// makeFocusable(); } } };