/* * Kontalk Android client * Copyright (C) 2017 Kontalk Devteam <devteam@kontalk.org> * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kontalk.ui.view; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import io.codetail.animation.SupportAnimator; import io.codetail.animation.ViewAnimationUtils; import io.codetail.widget.RevealFrameLayout; import org.kontalk.R; /** * Composite view for the attachment reveal frame layout. * Created mainly for handling animators concurrency. It seems like an overkill, * but I was getting crazy with race conditions. If someone has a better idea, * please propose a patch. * @author Daniele Ricci */ public class AttachmentRevealFrameLayout extends RevealFrameLayout { private View mContent; private SupportAnimator mHideAnimator; public AttachmentRevealFrameLayout(Context context) { super(context); } public AttachmentRevealFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public AttachmentRevealFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onFinishInflate() { super.onFinishInflate(); mContent = findViewById(R.id.circular_card); } public void show() { // stop all animations! mContent.clearAnimation(); setVisibility(VISIBLE); int right = mContent.getRight(); int top = mContent.getTop(); float f = (float) Math.sqrt(Math.pow(mContent.getWidth(), 2D) + Math.pow(mContent.getHeight(), 2D)); SupportAnimator showAnimator = ViewAnimationUtils.createCircularReveal(mContent, right, top, 0, f); setAnimatorParams(showAnimator); showAnimator.addListener(new SupportAnimator.AnimatorListener() { @Override public void onAnimationStart() { } @Override public void onAnimationEnd() { } @Override public void onAnimationCancel() { } @Override public void onAnimationRepeat() { } }); // create hide animation now mHideAnimator = showAnimator.reverse(); setAnimatorParams(mHideAnimator); mHideAnimator.addListener(new SupportAnimator.AnimatorListener() { @Override public void onAnimationStart() { } @Override public void onAnimationEnd() { hideNow(); } @Override public void onAnimationCancel() { } @Override public void onAnimationRepeat() { } }); showAnimator.start(); } public void hide() { hide(false); } public void hide(boolean instant) { // cancel show animation (if any) mContent.clearAnimation(); if (instant) { hideNow(); } else if (mHideAnimator != null && !mHideAnimator.isRunning()) { mHideAnimator.start(); } } public void toggle() { if (getVisibility() == VISIBLE) { hide(); } else { show(); } } public boolean isClosing() { return mHideAnimator != null && mHideAnimator.isRunning(); } void hideNow() { setVisibility(INVISIBLE); mHideAnimator = null; } private void setAnimatorParams(SupportAnimator anim) { anim.setInterpolator(new AccelerateDecelerateInterpolator()); anim.setDuration(250); } }