/** * */ package gilday.android.powerhour.view; import gilday.android.powerhour.R; import gilday.android.powerhour.data.PowerHour.NowPlaying; import gilday.android.powerhour.data.PreferenceRepository; import android.content.Context; import android.database.Cursor; import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.ToggleButton; /** * Cursor adapter which binds a Cursor for the Power Hour database to the playlist * edit list. Exposes an event which signifies when the user wishes to toggle the * omission property for a song item in the playlist * @author jgilday * */ public class PlaylistCursorAdapter extends CursorAdapter { private SongOmitHandler listener; private boolean isShuffle; /** * Holds the single instance of the OmitButtonHandler. Re-using * the same OmitToggleHandler instance saves on performance. */ private OmitButtonHandler internalButtonHandler; public PlaylistCursorAdapter(Context context, Cursor cursor, int flags) { super(context, cursor, flags); internalButtonHandler = new OmitButtonHandler(); isShuffle = new PreferenceRepository(context).isShuffle(); } @Override public void bindView(View view, Context context, Cursor cursor) { ViewHolder vh = (ViewHolder) view.getTag(); bindViewHolder(vh, cursor); } @Override public View newView(Context context, final Cursor cursor, ViewGroup parent) { // Inflate the views final LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.song_item, parent, false); // Create a viewholder to hold references to the views ViewHolder vh = new ViewHolder(); vh.positionView = (TextView)view.findViewById(R.id.songitem_position); vh.artistView = (TextView)view.findViewById(R.id.songitem_artist); vh.titleView = (TextView)view.findViewById(R.id.songitem_name); vh.omitToggleButton = (ToggleButton)view.findViewById(R.id.songitem_omit); view.setTag(vh); // Use helper function to bind cursor data to the views bindViewHolder(vh, cursor); // Clear out listeners in case they're still hanging around vh.omitToggleButton.setOnClickListener(null); // Register this listener vh.omitToggleButton.setOnClickListener(internalButtonHandler); return view; } public void setOmitToggleListener(SongOmitHandler listener) { this.listener = listener; } private void bindViewHolder(ViewHolder vh, Cursor cursor) { int position = isShuffle ? cursor.getInt(cursor.getColumnIndex(NowPlaying.SHUFFLE_POSITION)) : cursor.getInt(cursor.getColumnIndex(NowPlaying.POSITION)); vh.positionView.setText(String.valueOf(position)); vh.artistView.setText(cursor.getString(cursor.getColumnIndex(NowPlaying.ARTIST))); vh.titleView.setText(cursor.getString(cursor.getColumnIndex(NowPlaying.TITLE))); int omit = cursor.getInt(cursor.getColumnIndex(NowPlaying.OMIT)); // Put the song ID and isChecked in the toggle button's Tag reference // The song ID will help the onCheckedChanged event snag the song ID that it is relevant to vh.omitToggleButton.setTag(cursor.getInt(cursor.getColumnIndex(NowPlaying._ID))); vh.omitToggleButton.setChecked(omit <= 0); boolean enableSongItem = cursor.getInt(cursor.getColumnIndex(NowPlaying.PLAYED)) <= 0; vh.artistView.setEnabled(enableSongItem); vh.positionView.setEnabled(enableSongItem); vh.titleView.setEnabled(enableSongItem); vh.omitToggleButton.setEnabled(enableSongItem); } /** * The PlaylistCursorAdapter fires an event when a song is omitted from or marked for * re-inclusion in the now playing playlist. * @author jgilday * */ public interface SongOmitHandler { void onSongOmissionChanged(int songId, boolean isOmitted); } /** * Using this private class to catch the CompoundButton.OnClick * to handle this View based event internally and without having to expose a * public CompoundButton.OnCheckedChangeListener on PlaylistCursorAdapter * Better encapsulation of UI * Need to catch onClick instead of onCheckedChanged because the ContentProvider's interaction * with this CursorAdapter causes an infinite loop of onCheckedChanged and it chokes the main * thread * @author jgilday * */ private class OmitButtonHandler implements View.OnClickListener { public void onClick(View v) { // Forward this event on to a the OmitToggleListener in a way that // keeps all the View stuff encapsulated here if(listener != null) { boolean isChecked = ((ToggleButton)v).isChecked(); int songId = (Integer) v.getTag(); listener.onSongOmissionChanged(songId, !isChecked); } } } /** * View Holder Android pattern. Caches pointers to Views that make up each list * item view * @author jgilday * */ private class ViewHolder { public TextView positionView; public TextView artistView; public TextView titleView; public ToggleButton omitToggleButton; } }