diff --git a/res/layout/song_selector.xml b/res/layout/song_selector.xml
index 66ce897f..01356dc5 100644
--- a/res/layout/song_selector.xml
+++ b/res/layout/song_selector.xml
@@ -22,16 +22,16 @@
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
-
-
+
+ android:fastScrollEnabled="true" />
+ *
+ * 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 .
+ */
+
+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 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 newValues = new ArrayList();
+ 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)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;
+ }
+}
\ No newline at end of file
diff --git a/src/org/kreed/vanilla/AlbumAdapter.java b/src/org/kreed/vanilla/AlbumAdapter.java
new file mode 100644
index 00000000..6eaf2c87
--- /dev/null
+++ b/src/org/kreed/vanilla/AlbumAdapter.java
@@ -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 albums = new HashMap();
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/src/org/kreed/vanilla/ArtistAdapter.java b/src/org/kreed/vanilla/ArtistAdapter.java
new file mode 100644
index 00000000..26668d40
--- /dev/null
+++ b/src/org/kreed/vanilla/ArtistAdapter.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 Christopher Eby
+ *
+ * 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 .
+ */
+
+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 artists = new HashMap();
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/src/org/kreed/vanilla/Song.java b/src/org/kreed/vanilla/Song.java
index ed8d77d6..5b77acdf 100644
--- a/src/org/kreed/vanilla/Song.java
+++ b/src/org/kreed/vanilla/Song.java
@@ -195,4 +195,18 @@ public class Song implements Parcelable {
return a.title.compareTo(b.title);
}
}
+
+ public static class AlbumComparator implements Comparator {
+ public int compare(Song a, Song b)
+ {
+ return a.album.compareTo(b.album);
+ }
+ }
+
+ public static class ArtistComparator implements Comparator {
+ public int compare(Song a, Song b)
+ {
+ return a.artist.compareTo(b.artist);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/org/kreed/vanilla/SongAdapter.java b/src/org/kreed/vanilla/SongAdapter.java
index c8664e22..3bb05d77 100644
--- a/src/org/kreed/vanilla/SongAdapter.java
+++ b/src/org/kreed/vanilla/SongAdapter.java
@@ -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 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 newValues = new ArrayList();
- 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)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;
- }
}
\ No newline at end of file
diff --git a/src/org/kreed/vanilla/SongSelector.java b/src/org/kreed/vanilla/SongSelector.java
index 1aae49cb..bb408592 100644
--- a/src/org/kreed/vanilla/SongSelector.java
+++ b/src/org/kreed/vanilla/SongSelector.java
@@ -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("");
}
}
\ No newline at end of file