/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package me.zhanghai.android.douya.navigation.ui;
import android.accounts.Account;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.transitionseverywhere.ChangeTransform;
import com.transitionseverywhere.Fade;
import com.transitionseverywhere.Transition;
import com.transitionseverywhere.TransitionManager;
import com.transitionseverywhere.TransitionSet;
import butterknife.BindView;
import butterknife.BindViews;
import butterknife.ButterKnife;
import me.zhanghai.android.douya.R;
import me.zhanghai.android.douya.account.util.AccountUtils;
import me.zhanghai.android.douya.network.api.info.apiv2.SimpleUser;
import me.zhanghai.android.douya.network.api.info.apiv2.User;
import me.zhanghai.android.douya.ui.CrossfadeText;
import me.zhanghai.android.douya.util.DrawableUtils;
import me.zhanghai.android.douya.util.ImageUtils;
import me.zhanghai.android.douya.util.ViewUtils;
public class NavigationHeaderLayout extends FrameLayout {
@BindView(R.id.backdrop)
ImageView mBackdropImage;
@BindView(R.id.scrim)
View mScrimView;
@BindViews({R.id.avatar, R.id.fade_out_avatar,
R.id.recent_one_avatar, R.id.fade_out_recent_one_avatar,
R.id.recent_two_avatar, R.id.fade_out_recent_two_avatar})
ImageView[] mAvatarImages;
@BindView(R.id.avatar)
ImageView mAvatarImage;
@BindView(R.id.fade_out_avatar)
ImageView mFadeOutAvatarImage;
@BindView(R.id.recent_one_avatar)
ImageView mRecentOneAvatarImage;
@BindView(R.id.fade_out_recent_one_avatar)
ImageView mFadeOutRecentOneAvatarImage;
@BindView(R.id.recent_two_avatar)
ImageView mRecentTwoAvatarImage;
@BindView(R.id.fade_out_recent_two_avatar)
ImageView mFadeOutRecentTwoAvatarImage;
@BindView(R.id.info)
LinearLayout mInfoLayout;
@BindView(R.id.name)
TextView mNameText;
@BindView(R.id.description)
TextView mDescriptionText;
@BindView(R.id.dropDown)
ImageView mDropDownImage;
private Adapter mAdapter;
private Listener mListener;
private Account mActiveAccount;
private Account mRecentOneAccount;
private Account mRecentTwoAccount;
private boolean mAccountTransitionRunning;
private boolean mShowingAccountList;
public NavigationHeaderLayout(Context context) {
super(context);
init();
}
public NavigationHeaderLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public NavigationHeaderLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public NavigationHeaderLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
ViewUtils.inflateInto(R.layout.navigation_header_layout, this);
ButterKnife.bind(this);
mBackdropImage.setImageResource(R.drawable.profile_header_backdrop);
ViewCompat.setBackground(mScrimView, DrawableUtils.makeScrimDrawable());
mInfoLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
showAccountList(!mShowingAccountList);
}
});
}
public void setAdapter(Adapter adapter) {
mAdapter = adapter;
}
public void setListener(Listener listener) {
mListener = listener;
}
public void bind() {
if (mAdapter == null) {
return;
}
bindActiveUser();
bindRecentUsers();
}
public void onAccountListChanged() {
boolean needReload = !mActiveAccount.equals(AccountUtils.getActiveAccount());
bind();
if (mListener != null && needReload) {
mListener.onAccountTransitionStart();
mListener.onAccountTransitionEnd();
}
}
private void bindActiveUser() {
mActiveAccount = AccountUtils.getActiveAccount();
User user = mAdapter.getUser(mActiveAccount);
if (user != null) {
bindAvatarImage(mAvatarImage, user.getLargeAvatarOrAvatar());
mNameText.setText(user.name);
if (!TextUtils.isEmpty(user.signature)) {
mDescriptionText.setText(user.signature);
} else {
//noinspection deprecation
mDescriptionText.setText(user.uid);
}
} else {
SimpleUser partialUser = mAdapter.getPartialUser(mActiveAccount);
bindAvatarImage(mAvatarImage, null);
mNameText.setText(partialUser.name);
//noinspection deprecation
mDescriptionText.setText(partialUser.uid);
}
mAvatarImage.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (mAccountTransitionRunning) {
return;
}
if (mListener != null) {
mListener.openProfile(mActiveAccount);
}
}
});
mAvatarImage.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (mAccountTransitionRunning) {
return false;
}
if (mListener != null) {
mListener.openProfile(mActiveAccount);
}
return true;
}
});
//mBackdropImage.setImageResource();
}
private void bindRecentUsers() {
mRecentOneAccount = AccountUtils.getRecentOneAccount();
bindRecentUser(mRecentOneAvatarImage, mRecentOneAccount);
mRecentTwoAccount = AccountUtils.getRecentTwoAccount();
bindRecentUser(mRecentTwoAvatarImage, mRecentTwoAccount);
}
private void bindRecentUser(ImageView avatarImage, final Account account) {
if (account == null) {
avatarImage.setVisibility(GONE);
return;
}
avatarImage.setVisibility(VISIBLE);
User user = mAdapter.getUser(account);
if (user != null) {
bindAvatarImage(avatarImage, user.getLargeAvatarOrAvatar());
} else {
bindAvatarImage(avatarImage, null);
}
avatarImage.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
switchToAccountWithTransitionIfNotRunning(account);
}
});
avatarImage.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (mAccountTransitionRunning) {
return false;
}
if (mListener != null) {
mListener.openProfile(account);
}
return true;
}
});
}
private void bindAvatarImage(ImageView avatarImage, String avatarUrl) {
if (TextUtils.isEmpty(avatarUrl)) {
avatarImage.setImageResource(R.drawable.avatar_icon_white_inactive_64dp);
avatarImage.setTag(null);
return;
}
for (ImageView anotherAvatarImage : mAvatarImages) {
String anotherAvatarUrl = (String) anotherAvatarImage.getTag();
if (TextUtils.equals(anotherAvatarUrl , avatarUrl)) {
setAvatarImageFrom(avatarImage, anotherAvatarImage);
return;
}
}
ImageUtils.loadNavigationHeaderAvatar(avatarImage, avatarUrl);
}
private void setAvatarImageFrom(ImageView toAvatarImage, ImageView fromAvatarImage) {
if (toAvatarImage == fromAvatarImage) {
return;
}
toAvatarImage.setImageDrawable(fromAvatarImage.getDrawable());
toAvatarImage.setTag(fromAvatarImage.getTag());
}
public void switchToAccountWithTransitionIfNotRunning(Account account) {
if (mAccountTransitionRunning) {
return;
}
showAccountList(false);
if (AccountUtils.isActiveAccount(account)) {
return;
}
AccountUtils.setActiveAccount(account);
if (account.equals(mRecentOneAccount)) {
beginAvatarTransitionFromRecent(mRecentOneAvatarImage);
} else if (account.equals(mRecentTwoAccount)) {
beginAvatarTransitionFromRecent(mRecentTwoAvatarImage);
} else {
beginAvatarTransitionFromNonRecent();
}
bind();
}
private void beginAvatarTransitionFromRecent(ImageView recentAvatarImage) {
beginAvatarTransition(recentAvatarImage, mAvatarImage, null);
}
private void beginAvatarTransitionFromNonRecent() {
beginAvatarTransition(mAvatarImage, mRecentOneAvatarImage,
mRecentTwoAccount != null ? mRecentTwoAvatarImage : null);
}
private void beginAvatarTransition(ImageView moveAvatarOneImage, ImageView moveAvatarTwoImage,
ImageView moveAvatarThreeImage) {
ImageView appearAvatarImage = moveAvatarOneImage;
ImageView disappearAvatarImage = moveAvatarThreeImage != null ? moveAvatarThreeImage
: moveAvatarTwoImage;
ImageView fadeOutDisappearAvatarImage =
disappearAvatarImage == mAvatarImage ? mFadeOutAvatarImage
: disappearAvatarImage == mRecentOneAvatarImage ?
mFadeOutRecentOneAvatarImage : mFadeOutRecentTwoAvatarImage;
TransitionSet transitionSet = new TransitionSet();
int duration = ViewUtils.getLongAnimTime(getContext());
// Will be set on already added and newly added transitions.
transitionSet.setDuration(duration);
// NOTE: TransitionSet.setInterpolator() won't have any effect on platform versions.
// https://code.google.com/p/android/issues/detail?id=195495
transitionSet.setInterpolator(new FastOutSlowInInterpolator());
Fade fadeOutAvatar = new Fade(Fade.OUT);
setAvatarImageFrom(fadeOutDisappearAvatarImage, disappearAvatarImage);
fadeOutDisappearAvatarImage.setVisibility(VISIBLE);
fadeOutAvatar.addTarget(fadeOutDisappearAvatarImage);
transitionSet.addTransition(fadeOutAvatar);
// Make it finish before new avatar arrives.
fadeOutAvatar.setDuration(duration / 2);
Fade fadeInAvatar = new Fade(Fade.IN);
appearAvatarImage.setVisibility(INVISIBLE);
fadeInAvatar.addTarget(appearAvatarImage);
transitionSet.addTransition(fadeInAvatar);
ChangeTransform changeAppearAvatarTransform = new ChangeTransform();
appearAvatarImage.setScaleX(0.8f);
appearAvatarImage.setScaleY(0.8f);
changeAppearAvatarTransform.addTarget(appearAvatarImage);
transitionSet.addTransition(changeAppearAvatarTransform);
addChangeMoveToAvatarTransformToTransitionSet(moveAvatarOneImage, moveAvatarTwoImage,
transitionSet);
if (moveAvatarThreeImage != null) {
addChangeMoveToAvatarTransformToTransitionSet(moveAvatarTwoImage, moveAvatarThreeImage,
transitionSet);
}
CrossfadeText crossfadeText = new CrossfadeText();
crossfadeText.addTarget(mNameText);
crossfadeText.addTarget(mDescriptionText);
transitionSet.addTransition(crossfadeText);
transitionSet.addListener(new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
mAccountTransitionRunning = false;
mInfoLayout.setEnabled(true);
if (mListener != null) {
mListener.onAccountTransitionEnd();
}
}
});
mInfoLayout.setEnabled(false);
TransitionManager.beginDelayedTransition(this, transitionSet);
mAccountTransitionRunning = true;
if (mListener != null) {
mListener.onAccountTransitionStart();
}
fadeOutDisappearAvatarImage.setVisibility(INVISIBLE);
appearAvatarImage.setVisibility(VISIBLE);
appearAvatarImage.setScaleX(1);
appearAvatarImage.setScaleY(1);
resetMoveToAvatarTransform(moveAvatarTwoImage);
if (moveAvatarThreeImage != null) {
resetMoveToAvatarTransform(moveAvatarThreeImage);
}
}
private void addChangeMoveToAvatarTransformToTransitionSet(ImageView moveFromAvatarImage,
ImageView moveToAvatarImage,
TransitionSet transitionSet) {
ChangeTransform changeMoveToAvatarTransform = new ChangeTransform();
moveToAvatarImage.setX(moveFromAvatarImage.getLeft()
+ (moveFromAvatarImage.getWidth() - moveToAvatarImage.getWidth()) / 2);
moveToAvatarImage.setY(moveFromAvatarImage.getTop()
+ (moveFromAvatarImage.getHeight() - moveToAvatarImage.getHeight()) / 2);
moveToAvatarImage.setScaleX((float) ViewUtils.getWidthExcludingPadding(moveFromAvatarImage)
/ ViewUtils.getWidthExcludingPadding(moveToAvatarImage));
moveToAvatarImage.setScaleY((float) ViewUtils.getHeightExcludingPadding(moveFromAvatarImage)
/ ViewUtils.getHeightExcludingPadding(moveToAvatarImage));
changeMoveToAvatarTransform.addTarget(moveToAvatarImage);
transitionSet.addTransition(changeMoveToAvatarTransform);
}
private void resetMoveToAvatarTransform(ImageView moveToAvatarImage) {
moveToAvatarImage.setTranslationX(0);
moveToAvatarImage.setTranslationY(0);
moveToAvatarImage.setScaleX(1);
moveToAvatarImage.setScaleY(1);
}
public boolean isShowingAccountList() {
return mShowingAccountList;
}
public void setShowingAccountList(boolean showing) {
showAccountList(showing, false);
}
private void showAccountList(boolean show, boolean animate) {
if (mShowingAccountList == show) {
return;
}
if (mListener == null) {
return;
}
float rotation = show ? 180 : 0;
if (animate) {
mDropDownImage.animate()
.rotation(rotation)
.setDuration(ViewUtils.getShortAnimTime(getContext()))
.start();
} else {
mDropDownImage.setRotation(rotation);
}
mListener.showAccountList(show);
mShowingAccountList = show;
}
private void showAccountList(boolean show) {
showAccountList(show, true);
}
public interface Adapter {
SimpleUser getPartialUser(Account account);
User getUser(Account account);
}
public interface Listener {
void openProfile(Account account);
void showAccountList(boolean show);
void onAccountTransitionStart();
void onAccountTransitionEnd();
}
}