package org.edx.mobile.view.adapters; import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.drawable.StateListDrawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.widget.TextViewCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.Spinner; import android.widget.TextView; import com.joanzapata.iconify.Icon; import com.joanzapata.iconify.IconDrawable; import org.edx.mobile.R; import org.edx.mobile.interfaces.TextResourceProvider; import org.edx.mobile.view.CourseDiscussionPostsThreadFragment; /** * Adapter for the filter and sort spinners in {@link CourseDiscussionPostsThreadFragment} */ public class DiscussionPostsSpinnerAdapter extends ArrayAdapter<TextResourceProvider> { // Since the sort icon is constructed by combining two IconDrawable items, // we need to accept a DrawableFactory for the icon instead of just an // Iconify.IconValue item. public interface IconDrawableFactory { @NonNull Drawable createIcon(); } private static class IconDrawableFactoryImpl implements IconDrawableFactory { @NonNull private final Context context; @NonNull private final Icon icon; IconDrawableFactoryImpl(@NonNull Context context, @NonNull Icon icon) { this.context = context; this.icon = icon; } @Override @NonNull public IconDrawable createIcon() { return new IconDrawable(context, icon) .sizeRes(context, R.dimen.small_icon_size) .colorRes(context, R.color.edx_brand_primary_base); } } private static final int[] ACTIVATED_STATE_SET = new int[] { android.R.attr.state_activated }; @NonNull private final IconDrawableFactory iconDrawableFactory; // We need a reference to the Spinner that this adapter is set to, in // order to generate dropdown items that match it's content height. Since // the content height is the result of subtracting the popup background's // vertical padding from it's parent's height (this margin is set up on // the Spinner in order to properly align the popup), it's best to // calculate it dynamically instead of defining it in another dimen // resource, which would be subject to desynchronization from it's // sources. @NonNull private final Spinner spinner; public DiscussionPostsSpinnerAdapter(@NonNull Spinner spinner, @NonNull TextResourceProvider[] textResourceProviders, @NonNull Icon icon) { this(spinner, textResourceProviders, new IconDrawableFactoryImpl(spinner.getContext(), icon)); } public DiscussionPostsSpinnerAdapter(@NonNull Spinner spinner, @NonNull TextResourceProvider[] textResourceProviders, @NonNull IconDrawableFactory iconDrawableFactory) { super(spinner.getContext(), R.layout.row_discussion_thread_dropdown, textResourceProviders); this.iconDrawableFactory = iconDrawableFactory; this.spinner = spinner; } // The bounds are being set up manually instead of depending on the intrinsic // dimensions because the constructed sort icon has non-square dimensions, // which is not possible to set in IconDrawable. @NonNull private Drawable createIcon() { Drawable icon = iconDrawableFactory.createIcon(); if (icon.getIntrinsicWidth() >= 0 && icon.getIntrinsicHeight() >= 0 && icon.getBounds().isEmpty()) { icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); } return icon; } @Override @NonNull public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { TextView textView = initTextView(position, convertView, parent); if (textView != convertView) { TextViewCompat.setCompoundDrawablesRelative( textView, createIcon(), null, null, null); } return textView; } @Override @NonNull public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { TextView textView = initTextView(position, convertView, parent); if (textView != convertView) { Drawable icon = createIcon(); StateListDrawable statefulIcon = new StateListDrawable(); statefulIcon.setBounds(icon.getBounds()); statefulIcon.addState(ACTIVATED_STATE_SET, icon); TextViewCompat.setCompoundDrawablesRelative( textView, statefulIcon, null, null, null); } ViewGroup.LayoutParams layoutParams = textView.getLayoutParams(); if (layoutParams.height == ViewGroup.LayoutParams.MATCH_PARENT) { layoutParams.height = spinner.getHeight() - spinner.getPaddingTop() - spinner.getPaddingBottom(); } return textView; } // Initialize the TextView, pending the assignment of the (stateful or // stateless) icon. @NonNull private TextView initTextView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) (convertView != null ? convertView : LayoutInflater.from(getContext()).inflate( R.layout.row_discussion_thread_dropdown, parent, false)); textView.setText(getItem(position).getTextResource()); return textView; } }