public boolean presentFragment(
      final BaseFragment fragment,
      final boolean removeLast,
      boolean forceWithoutAnimation,
      boolean check) {
    if (checkTransitionAnimation()
        || delegate != null
            && check
            && !delegate.needPresentFragment(fragment, removeLast, forceWithoutAnimation, this)
        || !fragment.onFragmentCreate()) {
      return false;
    }
    if (parentActivity.getCurrentFocus() != null) {
      AndroidUtilities.hideKeyboard(parentActivity.getCurrentFocus());
      NotificationCenter.getInstance().postNotificationName(NotificationCenter.hideEmojiKeyboard);
    }
    boolean needAnimation =
        Build.VERSION.SDK_INT > 10
            && !forceWithoutAnimation
            && parentActivity
                .getSharedPreferences("mainconfig", Activity.MODE_PRIVATE)
                .getBoolean("view_animations", true);

    final BaseFragment currentFragment =
        !fragmentsStack.isEmpty() ? fragmentsStack.get(fragmentsStack.size() - 1) : null;

    fragment.setParentLayout(this);
    View fragmentView = fragment.createView(parentActivity.getLayoutInflater());
    if (fragment.needAddActionBar() && fragment.actionBar != null) {
      if (removeActionBarExtraHeight) {
        fragment.actionBar.setOccupyStatusBar(false);
      }
      ViewGroup parent = (ViewGroup) fragment.actionBar.getParent();
      if (parent != null) {
        parent.removeView(fragment.actionBar);
      }
      containerViewBack.addView(fragment.actionBar);
      fragment.actionBar.setTitleOverlayText(titleOverlayText);
    }

    containerViewBack.addView(fragmentView);
    ViewGroup.LayoutParams layoutParams = fragmentView.getLayoutParams();
    layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT;
    layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT;
    fragmentView.setLayoutParams(layoutParams);
    fragmentsStack.add(fragment);
    fragment.onResume();
    currentActionBar = fragment.actionBar;
    if (fragmentView.getBackground() == null) {
      fragmentView.setBackgroundColor(0xffffffff);
    }

    LinearLayoutContainer temp = containerView;
    containerView = containerViewBack;
    containerViewBack = temp;
    containerView.setVisibility(View.VISIBLE);
    setInnerTranslationX(0);

    bringChildToFront(containerView);

    if (!needAnimation) {
      presentFragmentInternalRemoveOld(removeLast, currentFragment);
      if (backgroundView != null) {
        backgroundView.setVisibility(VISIBLE);
      }
    }

    if (needAnimation) {
      if (useAlphaAnimations && fragmentsStack.size() == 1) {
        presentFragmentInternalRemoveOld(removeLast, currentFragment);

        ArrayList<Object> animators = new ArrayList<>();
        animators.add(ObjectAnimatorProxy.ofFloat(this, "alpha", 0.0f, 1.0f));
        if (backgroundView != null) {
          backgroundView.setVisibility(VISIBLE);
          animators.add(ObjectAnimatorProxy.ofFloat(backgroundView, "alpha", 0.0f, 1.0f));
        }

        currentAnimation = new AnimatorSetProxy();
        currentAnimation.playTogether(animators);
        currentAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
        currentAnimation.setDuration(200);
        currentAnimation.addListener(
            new AnimatorListenerAdapterProxy() {
              @Override
              public void onAnimationEnd(Object animation) {
                onAnimationEndCheck(false);
              }

              @Override
              public void onAnimationCancel(Object animation) {
                onAnimationEndCheck(false);
              }
            });
        currentAnimation.start();
      } else {
        transitionAnimationStartTime = System.currentTimeMillis();
        transitionAnimationInProgress = true;
        onOpenAnimationEndRunnable =
            new Runnable() {
              @Override
              public void run() {
                presentFragmentInternalRemoveOld(removeLast, currentFragment);
                fragment.onOpenAnimationEnd();
                ViewProxy.setTranslationX(containerView, 0);
              }
            };
        ViewProxy.setAlpha(containerView, 0.0f);
        ViewProxy.setTranslationX(containerView, 48.0f);
        currentAnimation = new AnimatorSetProxy();
        currentAnimation.playTogether(
            ObjectAnimatorProxy.ofFloat(containerView, "alpha", 0.0f, 1.0f),
            ObjectAnimatorProxy.ofFloat(containerView, "translationX", AndroidUtilities.dp(48), 0));
        currentAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
        currentAnimation.setDuration(200);
        currentAnimation.addListener(
            new AnimatorListenerAdapterProxy() {
              @Override
              public void onAnimationStart(Object animation) {
                transitionAnimationStartTime = System.currentTimeMillis();
              }

              @Override
              public void onAnimationEnd(Object animation) {
                onAnimationEndCheck(false);
              }

              @Override
              public void onAnimationCancel(Object animation) {
                onAnimationEndCheck(false);
              }
            });
        currentAnimation.start();
      }
    } else {
      if (backgroundView != null) {
        ViewProxy.setAlpha(backgroundView, 1.0f);
        backgroundView.setVisibility(VISIBLE);
      }
      fragment.onOpenAnimationEnd();
    }
    return true;
  }
  public void closeLastFragment(boolean animated) {
    if (delegate != null && !delegate.needCloseLastFragment(this)
        || checkTransitionAnimation()
        || fragmentsStack.isEmpty()) {
      return;
    }
    if (parentActivity.getCurrentFocus() != null) {
      AndroidUtilities.hideKeyboard(parentActivity.getCurrentFocus());
    }
    setInnerTranslationX(0);
    boolean needAnimation =
        Build.VERSION.SDK_INT > 10
            && animated
            && parentActivity
                .getSharedPreferences("mainconfig", Activity.MODE_PRIVATE)
                .getBoolean("view_animations", true);
    final BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1);
    BaseFragment previousFragment = null;
    if (fragmentsStack.size() > 1) {
      previousFragment = fragmentsStack.get(fragmentsStack.size() - 2);
    }

    if (previousFragment != null) {
      LinearLayoutContainer temp = containerView;
      containerView = containerViewBack;
      containerViewBack = temp;
      containerView.setVisibility(View.VISIBLE);

      previousFragment.setParentLayout(this);
      View fragmentView = previousFragment.createView(parentActivity.getLayoutInflater());
      if (previousFragment.needAddActionBar() && previousFragment.actionBar != null) {
        if (removeActionBarExtraHeight) {
          previousFragment.actionBar.setOccupyStatusBar(false);
        }
        ViewGroup parent = (ViewGroup) previousFragment.actionBar.getParent();
        if (parent != null) {
          parent.removeView(previousFragment.actionBar);
        }
        containerView.addView(previousFragment.actionBar);
        previousFragment.actionBar.setTitleOverlayText(titleOverlayText);
      }
      containerView.addView(fragmentView);
      ViewGroup.LayoutParams layoutParams = fragmentView.getLayoutParams();
      layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT;
      layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT;
      fragmentView.setLayoutParams(layoutParams);
      previousFragment.onResume();
      currentActionBar = previousFragment.actionBar;
      if (fragmentView.getBackground() == null) {
        fragmentView.setBackgroundColor(0xffffffff);
      }

      if (!needAnimation) {
        closeLastFragmentInternalRemoveOld(currentFragment);
      }

      if (needAnimation) {
        transitionAnimationStartTime = System.currentTimeMillis();
        transitionAnimationInProgress = true;
        onCloseAnimationEndRunnable =
            new Runnable() {
              @Override
              public void run() {
                closeLastFragmentInternalRemoveOld(currentFragment);
                ViewProxy.setTranslationX(containerViewBack, 0);
              }
            };

        currentAnimation = new AnimatorSetProxy();
        currentAnimation.playTogether(
            ObjectAnimatorProxy.ofFloat(containerViewBack, "alpha", 1.0f, 0.0f),
            ObjectAnimatorProxy.ofFloat(
                containerViewBack, "translationX", 0, AndroidUtilities.dp(48)));
        currentAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
        currentAnimation.setDuration(200);
        currentAnimation.addListener(
            new AnimatorListenerAdapterProxy() {
              @Override
              public void onAnimationStart(Object animation) {
                transitionAnimationStartTime = System.currentTimeMillis();
              }

              @Override
              public void onAnimationEnd(Object animation) {
                onAnimationEndCheck(false);
              }

              @Override
              public void onAnimationCancel(Object animation) {
                onAnimationEndCheck(false);
              }
            });
        currentAnimation.start();
      }
    } else {
      if (useAlphaAnimations) {
        transitionAnimationStartTime = System.currentTimeMillis();
        transitionAnimationInProgress = true;

        onCloseAnimationEndRunnable =
            new Runnable() {
              @Override
              public void run() {
                removeFragmentFromStack(currentFragment);
                setVisibility(GONE);
                if (backgroundView != null) {
                  backgroundView.setVisibility(GONE);
                }
                if (drawerLayoutContainer != null) {
                  drawerLayoutContainer.setAllowOpenDrawer(true);
                }
              }
            };

        ArrayList<Object> animators = new ArrayList<>();
        animators.add(ObjectAnimatorProxy.ofFloat(this, "alpha", 1.0f, 0.0f));
        if (backgroundView != null) {
          animators.add(ObjectAnimatorProxy.ofFloat(backgroundView, "alpha", 1.0f, 0.0f));
        }

        currentAnimation = new AnimatorSetProxy();
        currentAnimation.playTogether(animators);
        currentAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
        currentAnimation.setDuration(200);
        currentAnimation.addListener(
            new AnimatorListenerAdapterProxy() {
              @Override
              public void onAnimationStart(Object animation) {
                transitionAnimationStartTime = System.currentTimeMillis();
              }

              @Override
              public void onAnimationEnd(Object animation) {
                onAnimationEndCheck(false);
              }

              @Override
              public void onAnimationCancel(Object animation) {
                onAnimationEndCheck(false);
              }
            });
        currentAnimation.start();
      } else {
        removeFragmentFromStack(currentFragment);
        setVisibility(GONE);
        if (backgroundView != null) {
          backgroundView.setVisibility(GONE);
        }
      }
    }
  }
  public boolean onTouchEvent(MotionEvent ev) {
    if (!checkTransitionAnimation() && !inActionMode && !animationInProgress) {
      if (fragmentsStack.size() > 1) {
        if (ev != null
            && ev.getAction() == MotionEvent.ACTION_DOWN
            && !startedTracking
            && !maybeStartTracking) {
          BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1);
          if (!currentFragment.swipeBackEnabled) {
            return false;
          }
          startedTrackingPointerId = ev.getPointerId(0);
          maybeStartTracking = true;
          startedTrackingX = (int) ev.getX();
          startedTrackingY = (int) ev.getY();
          if (velocityTracker != null) {
            velocityTracker.clear();
          }
        } else if (ev != null
            && ev.getAction() == MotionEvent.ACTION_MOVE
            && ev.getPointerId(0) == startedTrackingPointerId) {
          if (velocityTracker == null) {
            velocityTracker = VelocityTracker.obtain();
          }
          int dx = Math.max(0, (int) (ev.getX() - startedTrackingX));
          int dy = Math.abs((int) ev.getY() - startedTrackingY);
          velocityTracker.addMovement(ev);
          if (maybeStartTracking
              && !startedTracking
              && dx >= AndroidUtilities.dp(10)
              && Math.abs(dx) / 3 > dy) {
            prepareForMoving(ev);
          } else if (startedTracking) {
            if (!beginTrackingSent) {
              if (parentActivity.getCurrentFocus() != null) {
                AndroidUtilities.hideKeyboard(parentActivity.getCurrentFocus());
              }
              BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1);
              currentFragment.onBeginSlide();
              beginTrackingSent = true;
            }
            ViewProxy.setTranslationX(containerView, dx);
            setInnerTranslationX(dx);
          }
        } else if (ev != null
            && ev.getPointerId(0) == startedTrackingPointerId
            && (ev.getAction() == MotionEvent.ACTION_CANCEL
                || ev.getAction() == MotionEvent.ACTION_UP
                || ev.getAction() == MotionEvent.ACTION_POINTER_UP)) {
          if (velocityTracker == null) {
            velocityTracker = VelocityTracker.obtain();
          }
          velocityTracker.computeCurrentVelocity(1000);
          if (!startedTracking) {
            float velX = velocityTracker.getXVelocity();
            float velY = velocityTracker.getYVelocity();
            if (velX >= 3500 && velX > velY) {
              prepareForMoving(ev);
              if (!beginTrackingSent) {
                if (((Activity) getContext()).getCurrentFocus() != null) {
                  AndroidUtilities.hideKeyboard(((Activity) getContext()).getCurrentFocus());
                }
                beginTrackingSent = true;
              }
            }
          }
          if (startedTracking) {
            float x = ViewProxy.getX(containerView);
            AnimatorSetProxy animatorSet = new AnimatorSetProxy();
            float velX = velocityTracker.getXVelocity();
            float velY = velocityTracker.getYVelocity();
            final boolean backAnimation =
                x < containerView.getMeasuredWidth() / 3.0f && (velX < 3500 || velX < velY);
            float distToMove = 0;
            if (!backAnimation) {
              distToMove = containerView.getMeasuredWidth() - x;
              animatorSet.playTogether(
                  ObjectAnimatorProxy.ofFloat(containerView, "x", containerView.getMeasuredWidth()),
                  ObjectAnimatorProxy.ofFloat(
                      this, "innerTranslationX", (float) containerView.getMeasuredWidth()));
            } else {
              distToMove = x;
              animatorSet.playTogether(
                  ObjectAnimatorProxy.ofFloat(containerView, "x", 0),
                  ObjectAnimatorProxy.ofFloat(this, "innerTranslationX", 0.0f));
            }

            animatorSet.setDuration(
                Math.max((int) (200.0f / containerView.getMeasuredWidth() * distToMove), 50));
            animatorSet.addListener(
                new AnimatorListenerAdapterProxy() {
                  @Override
                  public void onAnimationEnd(Object animator) {
                    onSlideAnimationEnd(backAnimation);
                  }

                  @Override
                  public void onAnimationCancel(Object animator) {
                    onSlideAnimationEnd(backAnimation);
                  }
                });
            animatorSet.start();
            animationInProgress = true;
          } else {
            maybeStartTracking = false;
            startedTracking = false;
          }
          if (velocityTracker != null) {
            velocityTracker.recycle();
            velocityTracker = null;
          }
        } else if (ev == null) {
          maybeStartTracking = false;
          startedTracking = false;
          if (velocityTracker != null) {
            velocityTracker.recycle();
            velocityTracker = null;
          }
        }
      }
      return startedTracking;
    }
    return false;
  }