mirror of https://github.com/NekoX-Dev/NekoX.git
3250 lines
143 KiB
Java
3250 lines
143 KiB
Java
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<PhotoFace> 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<VideoEditedInfo.MediaEntity> 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<VideoEditedInfo.MediaEntity> 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<TLRPC.InputDocument> getMasks() {
|
|
ArrayList<TLRPC.InputDocument> 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();
|
|
}
|
|
}
|