/* == This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2014, Enno Gottschalk <mrmaffen@googlemail.com>
*
* Tomahawk 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.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
package org.tomahawk.tomahawk_android.views;
import org.tomahawk.libtomahawk.collection.Collection;
import org.tomahawk.libtomahawk.resolver.PipeLine;
import org.tomahawk.libtomahawk.resolver.Resolver;
import org.tomahawk.libtomahawk.resolver.UserCollectionStubResolver;
import org.tomahawk.libtomahawk.utils.ViewUtils;
import org.tomahawk.tomahawk_android.R;
import org.tomahawk.tomahawk_android.TomahawkApp;
import org.tomahawk.tomahawk_android.listeners.OnSizeChangedListener;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class FancyDropDown extends FrameLayout {
private int mSelection;
private List<DropDownItemInfo> mItemInfos;
private DropDownListener mListener;
private boolean mShowing;
private boolean mIsAnimating;
private int mItemHeight;
private SparseArray<FrameLayout> mItemFrames;
public String mText;
private OnSizeChangedListener mOnSizeChangedListener;
private boolean mCanBeVisible = false;
public static class DropDownItemInfo {
public String mText;
public Resolver mResolver;
public boolean equals(DropDownItemInfo itemInfo) {
return (mText != null && mText.equals(itemInfo.mText))
|| (mText == null && itemInfo.mText == null)
&& mResolver == itemInfo.mResolver;
}
}
public interface DropDownListener {
void onDropDownItemSelected(int position);
void onCancel();
}
public FancyDropDown(Context context) {
super(context);
inflate(getContext(), R.layout.fancydropdown, this);
}
public FancyDropDown(Context context, AttributeSet attrs) {
super(context, attrs);
inflate(getContext(), R.layout.fancydropdown, this);
}
public void setup(int initialSelection, String selectedText,
List<DropDownItemInfo> dropDownItemInfos, DropDownListener dropDownListener) {
mListener = dropDownListener;
mText = selectedText;
((TextView) findViewById(R.id.textview_selected)).setText(mText);
mCanBeVisible = true;
if (dropDownItemInfos != null && dropDownItemInfos.size() > 0) {
// Do we really need to update? Do the new infos differ from the old ones?
boolean differingInfos = mItemInfos == null
|| mItemInfos.size() != dropDownItemInfos.size();
for (int i = 0; !differingInfos && i < mItemInfos.size(); i++) {
if (!mItemInfos.get(i).equals(dropDownItemInfos.get(i))) {
differingInfos = true;
}
}
if (differingInfos) {
mItemInfos = dropDownItemInfos;
mItemFrames = new SparseArray<>();
LinearLayout itemsContainer =
(LinearLayout) findViewById(R.id.dropdown_items_container);
itemsContainer.removeAllViews();
updateSelectedItem(initialSelection);
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = 0; i < mItemInfos.size(); i++) {
final LinearLayout item = (LinearLayout) inflater
.inflate(R.layout.fancydropdown_item, this, false);
final TextView textView = (TextView) item.findViewById(R.id.textview);
textView.setText(mItemInfos.get(i).mText.toUpperCase());
ImageView imageView = (ImageView) item.findViewById(R.id.imageview);
if (mItemInfos.get(i).mResolver != null) {
mItemInfos.get(i).mResolver.loadIconWhite(imageView, 0);
}
final int position = i;
item.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
hideDropDownList(position);
if (mListener != null) {
mListener.onDropDownItemSelected(position);
}
}
});
// We need a FrameLayout to hide the item when it's out of the FrameLayout's bounds
FrameLayout frameLayout = new FrameLayout(getContext());
frameLayout.setLayoutParams(
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
frameLayout.addView(item);
itemsContainer.addView(frameLayout);
mItemFrames.put(position, frameLayout);
}
ViewUtils.afterViewGlobalLayout(new ViewUtils.ViewRunnable(mItemFrames.get(0)) {
@Override
public void run() {
mItemHeight = mItemFrames.get(0).getHeight();
for (int i = 0; i < mItemFrames.size(); i++) {
mItemFrames.get(i).getChildAt(0).setY(mItemHeight * -1);
}
}
});
}
}
findViewById(R.id.selected_item_container).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mItemFrames != null && mItemFrames.size() > 1) {
if (mShowing) {
mListener.onCancel();
hideDropDownList(mSelection);
} else {
showDropDownList();
}
}
}
});
}
private void updateSelectedItem(int newSelection) {
mSelection = newSelection;
ImageView imageView = (ImageView) findViewById(R.id.imageview_selected);
if (mItemInfos != null) {
if (mItemInfos.get(mSelection).mResolver != null) {
mItemInfos.get(mSelection).mResolver.loadIconWhite(imageView, 0);
imageView.setVisibility(VISIBLE);
} else {
imageView.setVisibility(GONE);
}
} else {
imageView.setVisibility(GONE);
}
}
public void showDropDownList() {
if (!mIsAnimating && !isShowing()) {
animateDropDown(false, new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mShowing = true;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
}
public void hideDropDownList(int selectedItem) {
if (!mIsAnimating && isShowing()) {
updateSelectedItem(selectedItem);
animateDropDown(true, new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mShowing = false;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
}
public boolean isShowing() {
return mShowing;
}
private void animateDropDown(boolean reverse, Animation.AnimationListener listener) {
int startPos = reverse ? mItemFrames.size() - 1 : 0;
animateDropDownItem(startPos, reverse, 120, listener);
}
private void animateDropDownItem(final int position, final boolean reverse, final int duration,
final Animation.AnimationListener listener) {
if (reverse ? position >= 0
: mItemFrames != null && position < mItemFrames.size()) {
View item = mItemFrames.get(position).getChildAt(0);
item.setY(reverse ? 0 : mItemHeight * -1);
final ValueAnimator animator =
ObjectAnimator.ofFloat(item, "y", reverse ? mItemHeight * -1 : 0);
animator.setDuration(duration / mItemFrames.size());
animator.setInterpolator(new LinearInterpolator());
animator.start();
mIsAnimating = true;
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
int newPosition = reverse ? position - 1 : position + 1;
animateDropDownItem(newPosition, reverse, duration, listener);
animator.removeListener(this);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
} else {
mIsAnimating = false;
listener.onAnimationEnd(null);
}
}
public static List<DropDownItemInfo> convertToDropDownItemInfo(List<Collection> collections) {
List<FancyDropDown.DropDownItemInfo> dropDownItemInfos
= new ArrayList<>();
for (Collection collection : collections) {
FancyDropDown.DropDownItemInfo dropDownItemInfo =
new FancyDropDown.DropDownItemInfo();
if (TomahawkApp.PLUGINNAME_HATCHET.equals(collection.getId())) {
dropDownItemInfo.mText = TomahawkApp.getContext().getString(R.string.all);
} else if (TomahawkApp.PLUGINNAME_USERCOLLECTION.equals(collection.getId())) {
dropDownItemInfo.mText = TomahawkApp.getContext().getString(R.string.local);
dropDownItemInfo.mResolver = UserCollectionStubResolver.get();
} else {
Resolver resolver = PipeLine.get().getResolver(collection.getId());
dropDownItemInfo.mText = resolver.getId();
dropDownItemInfo.mResolver = resolver;
}
dropDownItemInfos.add(dropDownItemInfo);
}
return dropDownItemInfos;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mCanBeVisible) {
setVisibility(VISIBLE);
}
if (mOnSizeChangedListener != null) {
mOnSizeChangedListener.onSizeChanged(w, h, oldw, oldh);
}
}
public void setOnSizeChangedListener(OnSizeChangedListener listener) {
mOnSizeChangedListener = listener;
}
}