Show lists for all song selector tabs

This commit is contained in:
Christopher Eby 2010-03-08 03:05:03 -06:00
parent 12af3135f2
commit 4b5d43cced
7 changed files with 358 additions and 160 deletions

View File

@ -22,16 +22,16 @@
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
<ListView
android:id="@+id/artist_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="this is another tab" />
<TextView
android:fastScrollEnabled="true" />
<ListView
android:id="@+id/album_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="this is a third tab" />
android:fastScrollEnabled="true" />
<ListView
android:id="@+id/song_list"
android:layout_width="fill_parent"

View File

@ -0,0 +1,174 @@
/*
* Copyright (C) 2010 Christopher Eby <kreed@kreed.org>
*
* This file is part of Vanilla Music Player.
*
* Vanilla Music Player is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Vanilla Music Player 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.
*
* 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.kreed.vanilla;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
public abstract class AbstractAdapter extends BaseAdapter implements Filterable {
protected Context mContext;
private List<Song> mObjects;
private Song[] mAllObjects;
private ArrayFilter mFilter;
protected float mSize;
protected int mPadding;
public AbstractAdapter(Context context, Song[] allObjects)
{
mContext = context;
mAllObjects = allObjects;
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
mSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, metrics);
mPadding = (int)mSize / 2;
}
@Override
public boolean hasStableIds()
{
return true;
}
protected void updateViews(Song song, TextView upper, TextView lower)
{
}
public Filter getFilter()
{
if (mFilter == null)
mFilter = new ArrayFilter();
return mFilter;
}
private static final String[] mRanges = { ".", "[2abc]", "[3def]", "[4ghi]", "[5jkl]", "[6mno]", "[7pqrs]", "[8tuv]", "[9wxyz]"};
private static Matcher createMatcher(String input)
{
String patternString = "";
for (int i = 0, end = input.length(); i != end; ++i) {
char c = input.charAt(i);
int value = c - '1';
if (value >= 0 && value < 9)
patternString += mRanges[value];
else
patternString += c;
}
return Pattern.compile(patternString, Pattern.CASE_INSENSITIVE).matcher("");
}
private class ArrayFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence filter)
{
FilterResults results = new FilterResults();
if (filter == null || filter.length() == 0) {
results.values = Arrays.asList(mAllObjects);
results.count = mAllObjects.length;
} else {
String[] words = filter.toString().split("\\s+");
Matcher[] matchers = new Matcher[words.length];
for (int i = words.length; --i != -1; )
matchers[i] = createMatcher(words[i]);
int count = mAllObjects.length;
ArrayList<Song> newValues = new ArrayList<Song>();
newValues.ensureCapacity(count);
outer:
for (int i = 0; i != count; ++i) {
Song song = mAllObjects[i];
for (int j = matchers.length; --j != -1; ) {
if (song.artist != null && matchers[j].reset(song.artist).find())
continue;
if (song.album != null && matchers[j].reset(song.album).find())
continue;
if (song.title != null && matchers[j].reset(song.title).find())
continue;
continue outer;
}
newValues.add(song);
}
newValues.trimToSize();
results.values = newValues;
results.count = newValues.size();
}
return results;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results)
{
mObjects = (List<Song>)results.values;
if (results.count == 0)
notifyDataSetInvalidated();
else
notifyDataSetChanged();
}
}
public int getCount()
{
if (mObjects == null) {
if (mAllObjects == null)
return 0;
return mAllObjects.length;
}
return mObjects.size();
}
public Song get(int i)
{
if (mObjects == null) {
if (mAllObjects == null)
return null;
return mAllObjects[i];
}
return mObjects.get(i);
}
public Object getItem(int i)
{
return get(i);
}
public long getItemId(int i)
{
if (mObjects != null && mObjects.isEmpty())
return 0;
return get(i).id;
}
}

View File

@ -0,0 +1,64 @@
package org.kreed.vanilla;
import java.util.Arrays;
import java.util.HashMap;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
public class AlbumAdapter extends AbstractAdapter {
private static Song[] filter(Song[] songs)
{
HashMap<Integer, Song> albums = new HashMap<Integer, Song>();
for (int i = songs.length; --i != -1; ) {
Song song = songs[i];
if (!albums.containsKey(song.albumId))
albums.put(song.albumId, song);
}
Song[] result = albums.values().toArray(new Song[0]);
Arrays.sort(result, new Song.AlbumComparator());
return result;
}
public AlbumAdapter(Context context, Song[] allSongs)
{
super(context, filter(allSongs));
}
public View getView(int position, View convertView, ViewGroup parent)
{
LinearLayout view = null;
try {
view = (LinearLayout)convertView;
} catch (ClassCastException e) {
}
if (view == null) {
view = new LinearLayout(mContext);
view.setOrientation(LinearLayout.VERTICAL);
view.setPadding(mPadding, mPadding, mPadding, mPadding);
TextView title = new TextView(mContext);
title.setSingleLine();
title.setTextColor(Color.WHITE);
title.setTextSize(mSize);
title.setId(0);
view.addView(title);
TextView artist = new TextView(mContext);
artist.setSingleLine();
artist.setTextSize(mSize);
artist.setId(1);
view.addView(artist);
}
Song song = get(position);
((TextView)view.findViewById(0)).setText(song.album);
((TextView)view.findViewById(1)).setText(song.artist);
return view;
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2010 Christopher Eby <kreed@kreed.org>
*
* This file is part of Vanilla Music Player.
*
* Vanilla Music Player is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Vanilla Music Player 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.
*
* 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.kreed.vanilla;
import java.util.Arrays;
import java.util.HashMap;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class ArtistAdapter extends AbstractAdapter {
private static Song[] filter(Song[] songs)
{
HashMap<Integer, Song> artists = new HashMap<Integer, Song>();
for (int i = songs.length; --i != -1; ) {
Song song = songs[i];
if (!artists.containsKey(song.artistId))
artists.put(song.artistId, song);
}
Song[] result = artists.values().toArray(new Song[0]);
Arrays.sort(result, new Song.ArtistComparator());
return result;
}
public ArtistAdapter(Context context, Song[] allSongs)
{
super(context, filter(allSongs));
}
public View getView(int position, View convertView, ViewGroup parent)
{
TextView view = null;
try {
view = (TextView)convertView;
} catch (ClassCastException e) {
}
if (view == null) {
view = new TextView(mContext);
view.setPadding(mPadding, mPadding, mPadding, mPadding);
view.setSingleLine();
view.setTextColor(Color.WHITE);
view.setTextSize(mSize);
}
view.setText(get(position).artist);
return view;
}
}

View File

@ -195,4 +195,18 @@ public class Song implements Parcelable {
return a.title.compareTo(b.title);
}
}
public static class AlbumComparator implements Comparator<Song> {
public int compare(Song a, Song b)
{
return a.album.compareTo(b.album);
}
}
public static class ArtistComparator implements Comparator<Song> {
public int compare(Song a, Song b)
{
return a.artist.compareTo(b.artist);
}
}
}

View File

@ -18,47 +18,25 @@
package org.kreed.vanilla;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import android.graphics.Color;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.LinearLayout;
import android.widget.TextView;
public class SongAdapter extends BaseAdapter implements Filterable {
private Context mContext;
private List<Song> mObjects;
private Song[] mAllObjects;
private ArrayFilter mFilter;
private float mSize;
private int mPadding;
public SongAdapter(Context context)
public class SongAdapter extends AbstractAdapter {
private static Song[] sort(Song[] songs)
{
mContext = context;
mAllObjects = Song.getAllSongMetadata();
Arrays.sort(mAllObjects, new Song.TitleComparator());
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
mSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, metrics);
mPadding = (int)mSize / 2;
Arrays.sort(songs, new Song.TitleComparator());
return songs;
}
@Override
public boolean hasStableIds()
public SongAdapter(Context context, Song[] allSongs)
{
return true;
super(ContextApplication.getContext(), sort(allSongs));
}
public View getView(int position, View convertView, ViewGroup parent)
@ -88,120 +66,9 @@ public class SongAdapter extends BaseAdapter implements Filterable {
view.addView(artist);
}
((TextView)view.findViewById(0)).setText(mObjects.get(position).title);
((TextView)view.findViewById(1)).setText(mObjects.get(position).artist);
Song song = get(position);
((TextView)view.findViewById(0)).setText(song.title);
((TextView)view.findViewById(1)).setText(song.artist);
return view;
}
public Filter getFilter()
{
if (mFilter == null)
mFilter = new ArrayFilter();
return mFilter;
}
private static final String[] mRanges = { ".", "[2abc]", "[3def]", "[4ghi]", "[5jkl]", "[6mno]", "[7pqrs]", "[8tuv]", "[9wxyz]"};
private static Matcher createMatcher(String input)
{
String patternString = "";
for (int i = 0, end = input.length(); i != end; ++i) {
char c = input.charAt(i);
int value = c - '1';
if (value >= 0 && value < 9)
patternString += mRanges[value];
else
patternString += c;
}
return Pattern.compile(patternString, Pattern.CASE_INSENSITIVE).matcher("");
}
private class ArrayFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence filter)
{
FilterResults results = new FilterResults();
if (filter == null || filter.length() == 0) {
results.values = Arrays.asList(mAllObjects);
results.count = mAllObjects.length;
} else {
String[] words = filter.toString().split("\\s+");
Matcher[] matchers = new Matcher[words.length];
for (int i = words.length; --i != -1; )
matchers[i] = createMatcher(words[i]);
int count = mAllObjects.length;
ArrayList<Song> newValues = new ArrayList<Song>();
newValues.ensureCapacity(count);
outer:
for (int i = 0; i != count; ++i) {
Song song = mAllObjects[i];
for (int j = matchers.length; --j != -1; ) {
if (song.artist != null && matchers[j].reset(song.artist).find())
continue;
if (song.album != null && matchers[j].reset(song.album).find())
continue;
if (song.title != null && matchers[j].reset(song.title).find())
continue;
continue outer;
}
newValues.add(song);
}
newValues.trimToSize();
results.values = newValues;
results.count = newValues.size();
}
return results;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results)
{
mObjects = (List<Song>)results.values;
if (results.count == 0)
notifyDataSetInvalidated();
else
notifyDataSetChanged();
}
}
public int getCount()
{
if (mObjects == null) {
if (mAllObjects == null)
return 0;
return mAllObjects.length;
}
return mObjects.size();
}
public Object getItem(int position)
{
if (mObjects == null) {
if (mAllObjects == null)
return 0;
return mAllObjects[position];
}
return mObjects.get(position);
}
public long getItemId(int position)
{
if (mObjects == null) {
if (mAllObjects == null)
return 0;
return mAllObjects[position].id;
}
if (mObjects.isEmpty())
return 0;
return mObjects.get(position).id;
}
}

View File

@ -39,9 +39,11 @@ import android.widget.TextView;
public class SongSelector extends TabActivity implements AdapterView.OnItemClickListener, TextWatcher, View.OnClickListener {
private TabHost mTabHost;
private SongAdapter mAdapter;
private ListView mListView;
private TextView mTextView;
private TextView mTextFilter;
private AbstractAdapter mArtistAdapter;
private AbstractAdapter mAlbumAdapter;
private AbstractAdapter mSongAdapter;
@Override
public void onCreate(Bundle icicle)
@ -59,14 +61,23 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick
mTabHost.addTab(mTabHost.newTabSpec("tab_albums").setIndicator(res.getText(R.string.albums), res.getDrawable(R.drawable.tab_albums)).setContent(R.id.album_list));
mTabHost.addTab(mTabHost.newTabSpec("tab_songs").setIndicator(res.getText(R.string.songs), res.getDrawable(R.drawable.tab_songs)).setContent(R.id.song_list));
mAdapter = new SongAdapter(this);
Song[] songs = Song.getAllSongMetadata();
mArtistAdapter = new ArtistAdapter(this, songs);
mAlbumAdapter = new AlbumAdapter(this, songs);
mSongAdapter = new SongAdapter(this, songs);
mListView = (ListView)findViewById(R.id.song_list);
mListView.setAdapter(mAdapter);
mListView.setOnItemClickListener(this);
ListView artistView = (ListView)findViewById(R.id.artist_list);
artistView.setAdapter(mArtistAdapter);
mTextView = (TextView)findViewById(R.id.filter_text);
mTextView.addTextChangedListener(this);
ListView albumView = (ListView)findViewById(R.id.album_list);
albumView.setAdapter(mAlbumAdapter);
ListView songView = (ListView)findViewById(R.id.song_list);
songView.setAdapter(mSongAdapter);
songView.setOnItemClickListener(this);
mTextFilter = (TextView)findViewById(R.id.filter_text);
mTextFilter.addTextChangedListener(this);
View clearButton = findViewById(R.id.clear_button);
clearButton.setOnClickListener(this);
@ -79,7 +90,7 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick
inputType = InputType.TYPE_TEXT_VARIATION_FILTER;
else
inputType = InputType.TYPE_CLASS_TEXT;
mTextView.setInputType(inputType);
mTextFilter.setInputType(inputType);
}
@Override
@ -88,8 +99,8 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick
if (super.onKeyDown(keyCode, event))
return true;
mTextView.requestFocus();
return mTextView.onKeyDown(keyCode, event);
mTextFilter.requestFocus();
return mTextFilter.onKeyDown(keyCode, event);
}
public void onItemClick(AdapterView<?> list, View view, int pos, long id)
@ -109,11 +120,11 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick
public void onTextChanged(CharSequence s, int start, int before, int count)
{
mAdapter.getFilter().filter(s);
mSongAdapter.getFilter().filter(s);
}
public void onClick(View view)
{
mTextView.setText("");
mTextFilter.setText("");
}
}