Customizable library tab order
This commit is contained in:
parent
6c6754cff0
commit
dabacbbd49
@ -125,6 +125,9 @@ THE SOFTWARE.
|
||||
<activity
|
||||
android:name="PreferencesActivity"
|
||||
android:theme="@style/BackActionBar" />
|
||||
<activity
|
||||
android:name="TabOrderActivity"
|
||||
android:theme="@style/BackActionBar" />
|
||||
<meta-data
|
||||
android:name="com.google.android.backup.api_key"
|
||||
android:value="AEdPqrEAAAAIH6Xcxa4hn6sHN1m4jMpi4MFFFMP5sv3XhFuWeA" />
|
||||
|
@ -22,9 +22,8 @@ THE SOFTWARE.
|
||||
-->
|
||||
<org.kreed.vanilla.DragListView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/playlist"
|
||||
android:id="@+id/list"
|
||||
android:fastScrollEnabled="true"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="1dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
@ -23,7 +23,6 @@ THE SOFTWARE.
|
||||
<org.kreed.vanilla.DragTextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:padding="3dip"
|
||||
android:minHeight="44dip"
|
||||
android:singleLine="true"
|
||||
android:textColor="#ffff"
|
||||
android:gravity="left|center_vertical" />
|
||||
|
57
res/layout/tab_order.xml
Normal file
57
res/layout/tab_order.xml
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:divider="?android:attr/dividerHorizontal"
|
||||
android:showDividers="middle"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="fill_parent">
|
||||
<org.kreed.vanilla.DragListView
|
||||
android:id="@+id/list"
|
||||
android:divider="@null"
|
||||
android:layout_height="0px"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:choiceMode="multipleChoice" />
|
||||
<LinearLayout
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<Button
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:id="@+id/restore_default"
|
||||
android:layout_width="0px"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/restore_default" />
|
||||
<Button
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:id="@+id/done"
|
||||
android:layout_width="0px"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/done" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
30
res/layout/tab_order_row.xml
Normal file
30
res/layout/tab_order_row.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
<org.kreed.vanilla.DragTextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:padding="3dip"
|
||||
android:singleLine="true"
|
||||
android:textColor="#ffff"
|
||||
android:drawableLeft="@drawable/grabber"
|
||||
android:drawableRight="?android:attr/listChoiceIndicatorMultiple"
|
||||
android:gravity="left|center_vertical" />
|
@ -185,6 +185,10 @@ THE SOFTWARE.
|
||||
<string name="scan_in_progress">Scan in progress…</string>
|
||||
<string name="finished_scanning">Finished scanning. Tap to scan again.</string>
|
||||
|
||||
<string name="tabs">Tab Order</string>
|
||||
<string name="customize_tab_order">Adjust the order and visibility of library tabs</string>
|
||||
<string name="restore_default">Restore default</string>
|
||||
|
||||
<!-- The following are for the list preferences -->
|
||||
<string name="last_used_action">Last used action</string>
|
||||
|
||||
|
@ -113,6 +113,7 @@ THE SOFTWARE.
|
||||
android:title="@string/controls_in_selector_title"
|
||||
android:summary="@string/controls_in_selector_summary"
|
||||
android:defaultValue="false" />
|
||||
<org.kreed.vanilla.TabOrderPreference />
|
||||
<org.kreed.vanilla.ListPreferenceSummary
|
||||
android:key="default_action_int"
|
||||
android:title="@string/default_action_title"
|
||||
|
@ -65,25 +65,13 @@ public class CompatHoneycomb {
|
||||
};
|
||||
|
||||
ActionBar ab = activity.getActionBar();
|
||||
ab.addTab(ab.newTab()
|
||||
.setText(R.string.artists)
|
||||
.setTabListener(listener));
|
||||
ab.addTab(ab.newTab()
|
||||
.setText(R.string.albums)
|
||||
.setTabListener(listener));
|
||||
ab.addTab(ab.newTab()
|
||||
.setText(R.string.songs)
|
||||
.setTabListener(listener));
|
||||
ab.addTab(ab.newTab()
|
||||
.setText(R.string.playlists)
|
||||
.setTabListener(listener));
|
||||
ab.addTab(ab.newTab()
|
||||
.setText(R.string.genres)
|
||||
.setTabListener(listener));
|
||||
ab.addTab(ab.newTab()
|
||||
.setText(R.string.files)
|
||||
.setTabListener(listener));
|
||||
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||
ab.removeAllTabs();
|
||||
int[] order = activity.mPagerAdapter.mTabOrder;
|
||||
int[] titles = LibraryPagerAdapter.TITLES;
|
||||
for (int i = 0, n = activity.mPagerAdapter.getCount(); i != n; ++i) {
|
||||
ab.addTab(ab.newTab().setText(titles[order[i]]).setTabListener(listener));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,7 +108,9 @@ public class CompatHoneycomb {
|
||||
public static void selectTab(Activity activity, int position)
|
||||
{
|
||||
ActionBar ab = activity.getActionBar();
|
||||
ab.selectTab(ab.getTabAt(position));
|
||||
if (position < ab.getTabCount()) {
|
||||
ab.selectTab(ab.getTabAt(position));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,6 +28,7 @@ import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
/**
|
||||
@ -36,7 +37,7 @@ import android.widget.ListView;
|
||||
* This implementation has some restrictions:
|
||||
* Footers are unsupported
|
||||
* All non-header views must have the same height
|
||||
* The adapter must be a PlaylistAdapter
|
||||
* The adapter must implement DragAdapter
|
||||
*
|
||||
* Dragging disabled by default. Enable it with
|
||||
* {@link DragListView#setEditable(boolean)}.
|
||||
@ -45,6 +46,20 @@ import android.widget.ListView;
|
||||
* HACKY. : /
|
||||
*/
|
||||
public class DragListView extends ListView implements Handler.Callback {
|
||||
/**
|
||||
* Adapter that implements move and remove operations.
|
||||
*/
|
||||
public interface DragAdapter extends ListAdapter {
|
||||
/**
|
||||
* Remove the element at position from and insert it at position to.
|
||||
*/
|
||||
public void move(int from, int to);
|
||||
/**
|
||||
* Remove the element at the given position.
|
||||
*/
|
||||
public void remove(int position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sent to scroll the list up or down when the dragged view is near the
|
||||
* top or bottom of the list.
|
||||
@ -53,11 +68,11 @@ public class DragListView extends ListView implements Handler.Callback {
|
||||
/**
|
||||
* Height of each row in dip.
|
||||
*/
|
||||
private static final int ROW_HEIGHT = 44;
|
||||
public static final int ROW_HEIGHT = 44;
|
||||
/**
|
||||
* Padding for each row in dip.
|
||||
*/
|
||||
private static final int PADDING = 3;
|
||||
public static final int PADDING = 3;
|
||||
/**
|
||||
* Background color of row while it is being dragged.
|
||||
*/
|
||||
@ -73,7 +88,7 @@ public class DragListView extends ListView implements Handler.Callback {
|
||||
/**
|
||||
* The adapter that will be called to move/remove rows.
|
||||
*/
|
||||
private PlaylistAdapter mAdapter;
|
||||
private DragAdapter mAdapter;
|
||||
/**
|
||||
* True to allow dragging; false otherwise.
|
||||
*/
|
||||
@ -135,13 +150,13 @@ public class DragListView extends ListView implements Handler.Callback {
|
||||
/**
|
||||
* This should be called instead of
|
||||
* {@link ListView#setAdapter(android.widget.ListAdapter)}.
|
||||
* DragListView requires a PlaylistAdapter to handle move/remove callbacks
|
||||
* DragListView requires a DragAdapter to handle move/remove callbacks
|
||||
* from dragging.
|
||||
*
|
||||
* @param adapter The adapter to use. Will be passed to
|
||||
* {@link ListView#setAdapter(android.widget.ListAdapter)}.
|
||||
*/
|
||||
public void setAdapter(PlaylistAdapter adapter)
|
||||
public void setAdapter(DragAdapter adapter)
|
||||
{
|
||||
super.setAdapter(adapter);
|
||||
// Keep track of adapter here since getAdapter() will return a wrapper
|
||||
@ -217,13 +232,13 @@ public class DragListView extends ListView implements Handler.Callback {
|
||||
*/
|
||||
private void unExpandViews()
|
||||
{
|
||||
int padding = mPadding;
|
||||
for (int i = 0, count = getChildCount(); i != count; ++i) {
|
||||
View view = getChildAt(i);
|
||||
ViewGroup.LayoutParams params = view.getLayoutParams();
|
||||
params.height = 0;
|
||||
view.setLayoutParams(params);
|
||||
view.setVisibility(View.VISIBLE);
|
||||
int padding = mPadding;
|
||||
view.setPadding(padding, padding, padding, padding);
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,9 @@ package org.kreed.vanilla;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.Checkable;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
@ -33,16 +35,42 @@ import android.widget.TextView;
|
||||
*
|
||||
* We draw the divider here rather than with ListView.setDivider() so we don't
|
||||
* have duplicate dividers when hiding a row for a drag.
|
||||
*
|
||||
* This also implements the Checkable interface to provide checking for
|
||||
* TabOrderActivity. CheckedTextView also provides this, but unfortunately its
|
||||
* check-mark ignores padding so it can't be used with DragListView's expansion
|
||||
* code.
|
||||
*/
|
||||
public class DragTextView extends TextView {
|
||||
public class DragTextView extends TextView implements Checkable {
|
||||
private final Paint mPaint;
|
||||
private boolean mChecked;
|
||||
/**
|
||||
* Check mark drawable to update with checked state. This drawable is set
|
||||
* as the TextView's right compound drawable, so TextView will handle the
|
||||
* drawing.
|
||||
*/
|
||||
private final Drawable mCheckMarkDrawable;
|
||||
/**
|
||||
* The preferred height of the view in pixels. Set to DragListView.ROW_HEIGHT.
|
||||
*/
|
||||
private final int mHeight;
|
||||
|
||||
private static final int[] CHECKED_STATE_SET = {
|
||||
android.R.attr.state_checked
|
||||
};
|
||||
|
||||
public DragTextView(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setColor(0xff444444);
|
||||
mPaint = paint;
|
||||
Drawable[] drawables = getCompoundDrawables();
|
||||
mCheckMarkDrawable = drawables[2];
|
||||
|
||||
float density = context.getResources().getDisplayMetrics().density;
|
||||
mHeight = (int)(DragListView.ROW_HEIGHT * density);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -52,10 +80,57 @@ public class DragTextView extends TextView {
|
||||
if (height <= 1)
|
||||
return;
|
||||
super.onDraw(canvas);
|
||||
if (getDrawingCacheBackgroundColor() != DragListView.DRAG_COLOR) {
|
||||
if (getDrawingCacheBackgroundColor() != DragListView.DRAG_COLOR && getPaddingBottom() < getHeight() / 2) {
|
||||
// only draw divider when not dragging
|
||||
float h = height - 1;
|
||||
canvas.drawLine(0, h, getWidth(), h, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked()
|
||||
{
|
||||
return mChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked)
|
||||
{
|
||||
mChecked = checked;
|
||||
refreshDrawableState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggle()
|
||||
{
|
||||
setChecked(!mChecked);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] onCreateDrawableState(int extraSpace)
|
||||
{
|
||||
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
|
||||
if (mChecked) {
|
||||
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
|
||||
}
|
||||
return drawableState;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawableStateChanged()
|
||||
{
|
||||
super.drawableStateChanged();
|
||||
|
||||
if (mCheckMarkDrawable != null) {
|
||||
int[] myDrawableState = getDrawableState();
|
||||
mCheckMarkDrawable.setState(myDrawableState);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasure(int widthSpec, int heightSpec)
|
||||
{
|
||||
setMeasuredDimension(MeasureSpec.getSize(widthSpec), resolveSize(mHeight, heightSpec));
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,7 @@ public class LibraryActivity
|
||||
SongTimeline.MODE_PLAY_ID_FIRST, SongTimeline.MODE_ENQUEUE_ID_FIRST };
|
||||
|
||||
public ViewPager mViewPager;
|
||||
private TabPageIndicator mTabs;
|
||||
|
||||
private View mSearchBox;
|
||||
private boolean mSearchBoxVisible;
|
||||
@ -183,7 +184,6 @@ public class LibraryActivity
|
||||
mViewPager = pager;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
CompatHoneycomb.addActionBarTabs(this);
|
||||
pager.setOnPageChangeListener(pagerAdapter);
|
||||
|
||||
View controls = getLayoutInflater().inflate(R.layout.actionbar_controls, null);
|
||||
@ -196,6 +196,7 @@ public class LibraryActivity
|
||||
TabPageIndicator tabs = new TabPageIndicator(this);
|
||||
tabs.setViewPager(pager);
|
||||
tabs.setOnPageChangeListener(pagerAdapter);
|
||||
mTabs = tabs;
|
||||
|
||||
LinearLayout content = (LinearLayout)findViewById(R.id.content);
|
||||
content.addView(tabs, 0, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
|
||||
@ -239,11 +240,17 @@ public class LibraryActivity
|
||||
super.onStart();
|
||||
|
||||
SharedPreferences settings = PlaybackService.getSettings(this);
|
||||
|
||||
if (settings.getBoolean("controls_in_selector", false) != (mControls != null)) {
|
||||
finish();
|
||||
startActivity(new Intent(this, LibraryActivity.class));
|
||||
}
|
||||
if (mPagerAdapter.loadTabOrder()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
CompatHoneycomb.addActionBarTabs(this);
|
||||
} else {
|
||||
mTabs.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
mDefaultAction = Integer.parseInt(settings.getString("default_action_int", "0"));
|
||||
mLastActedId = LibraryAdapter.INVALID_ID;
|
||||
updateHeaders();
|
||||
@ -273,7 +280,7 @@ public class LibraryActivity
|
||||
String data = String.format("album_id=%d", albumId);
|
||||
Limiter limiter = new Limiter(MediaUtils.TYPE_ALBUM, fields, data);
|
||||
int tab = mPagerAdapter.setLimiter(limiter);
|
||||
if (tab == mViewPager.getCurrentItem())
|
||||
if (tab == -1 || tab == mViewPager.getCurrentItem())
|
||||
updateLimiterViews();
|
||||
else
|
||||
mViewPager.setCurrentItem(tab);
|
||||
@ -386,7 +393,7 @@ public class LibraryActivity
|
||||
mode = modeForAction[mode];
|
||||
|
||||
QueryTask query = buildQueryFromIntent(intent, false, all);
|
||||
PlaybackService.get(this).addSongs(mode, query, intent.getIntExtra("type", -1));
|
||||
PlaybackService.get(this).addSongs(mode, query, intent.getIntExtra("type", MediaUtils.TYPE_INVALID));
|
||||
|
||||
mLastActedId = id;
|
||||
|
||||
@ -405,10 +412,10 @@ public class LibraryActivity
|
||||
*/
|
||||
private void expand(Intent intent)
|
||||
{
|
||||
int type = intent.getIntExtra("type", 1);
|
||||
int type = intent.getIntExtra("type", MediaUtils.TYPE_INVALID);
|
||||
long id = intent.getLongExtra("id", LibraryAdapter.INVALID_ID);
|
||||
int tab = mPagerAdapter.setLimiter(mPagerAdapter.mAdapters[type - 1].buildLimiter(id));
|
||||
if (tab == mViewPager.getCurrentItem())
|
||||
int tab = mPagerAdapter.setLimiter(mPagerAdapter.mAdapters[type].buildLimiter(id));
|
||||
if (tab == -1 || tab == mViewPager.getCurrentItem())
|
||||
updateLimiterViews();
|
||||
else
|
||||
mViewPager.setCurrentItem(tab);
|
||||
@ -455,7 +462,7 @@ public class LibraryActivity
|
||||
*/
|
||||
public void onItemExpanded(Intent rowData)
|
||||
{
|
||||
int type = rowData.getIntExtra(LibraryAdapter.DATA_TYPE, -1);
|
||||
int type = rowData.getIntExtra(LibraryAdapter.DATA_TYPE, MediaUtils.TYPE_INVALID);
|
||||
if (type == MediaUtils.TYPE_PLAYLIST)
|
||||
editPlaylist(rowData);
|
||||
else
|
||||
@ -575,7 +582,7 @@ public class LibraryActivity
|
||||
*/
|
||||
private QueryTask buildQueryFromIntent(Intent intent, boolean empty, boolean all)
|
||||
{
|
||||
int type = intent.getIntExtra("type", 1);
|
||||
int type = intent.getIntExtra("type", MediaUtils.TYPE_INVALID);
|
||||
|
||||
String[] projection;
|
||||
if (type == MediaUtils.TYPE_PLAYLIST)
|
||||
@ -588,7 +595,7 @@ public class LibraryActivity
|
||||
if (type == MediaUtils.TYPE_FILE) {
|
||||
query = MediaUtils.buildFileQuery(intent.getStringExtra("file"), projection);
|
||||
} else if (all || id == LibraryAdapter.HEADER_ID) {
|
||||
query = ((MediaAdapter)mPagerAdapter.mAdapters[type - 1]).buildSongQuery(projection);
|
||||
query = ((MediaAdapter)mPagerAdapter.mAdapters[type]).buildSongQuery(projection);
|
||||
query.setExtra(id);
|
||||
} else {
|
||||
query = MediaUtils.buildQuery(type, id, projection, null);
|
||||
@ -622,7 +629,7 @@ public class LibraryActivity
|
||||
menu.add(0, MENU_ENQUEUE_ALL, 0, R.string.enqueue_all).setIntent(rowData);
|
||||
menu.addSubMenu(0, MENU_ADD_TO_PLAYLIST, 0, R.string.add_to_playlist).getItem().setIntent(rowData);
|
||||
} else {
|
||||
int type = rowData.getIntExtra(LibraryAdapter.DATA_TYPE, -1);
|
||||
int type = rowData.getIntExtra(LibraryAdapter.DATA_TYPE, MediaUtils.TYPE_INVALID);
|
||||
boolean isAllAdapter = type <= MediaUtils.TYPE_SONG;
|
||||
|
||||
menu.setHeaderTitle(rowData.getStringExtra(LibraryAdapter.DATA_TITLE));
|
||||
@ -680,8 +687,8 @@ public class LibraryActivity
|
||||
*/
|
||||
private void delete(Intent intent)
|
||||
{
|
||||
int type = intent.getIntExtra("type", 1);
|
||||
long id = intent.getLongExtra("id", -1);
|
||||
int type = intent.getIntExtra("type", MediaUtils.TYPE_INVALID);
|
||||
long id = intent.getLongExtra("id", LibraryAdapter.INVALID_ID);
|
||||
String message = null;
|
||||
Resources res = getResources();
|
||||
|
||||
@ -1005,17 +1012,18 @@ public class LibraryActivity
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new adapter has been made visible.
|
||||
* Called when a new page becomes visible.
|
||||
*
|
||||
* @param position The position of the new page.
|
||||
* @param adapter The new visible adapter.
|
||||
*/
|
||||
public void onAdapterSelected(LibraryAdapter adapter)
|
||||
public void onPageChanged(int position, LibraryAdapter adapter)
|
||||
{
|
||||
mCurrentAdapter = adapter;
|
||||
mLastActedId = LibraryAdapter.INVALID_ID;
|
||||
updateLimiterViews();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
CompatHoneycomb.selectTab(this, mViewPager.getCurrentItem());
|
||||
CompatHoneycomb.selectTab(this, position);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* PagerAdapter that manages the library media ListViews.
|
||||
@ -54,41 +55,64 @@ public class LibraryPagerAdapter
|
||||
, AdapterView.OnItemClickListener
|
||||
{
|
||||
/**
|
||||
* The number of adapters/lists (determines array sizes).
|
||||
* The number of unique list types. The number of visible lists may be
|
||||
* smaller.
|
||||
*/
|
||||
private static final int ADAPTER_COUNT = 6;
|
||||
public static final int MAX_ADAPTER_COUNT = 6;
|
||||
/**
|
||||
* The human-readable title for each page.
|
||||
* The human-readable title for each list. The positions correspond to the
|
||||
* MediaUtils ids, so e.g. TITLES[MediaUtils.TYPE_SONG] = R.string.songs
|
||||
*/
|
||||
private static final int[] TITLES = { R.string.artists, R.string.albums, R.string.songs,
|
||||
R.string.playlists, R.string.genres, R.string.files };
|
||||
|
||||
public static final int[] TITLES = { R.string.artists, R.string.albums, R.string.songs,
|
||||
R.string.playlists, R.string.genres, R.string.files };
|
||||
/**
|
||||
* The ListView for each adapter, in the same order as MediaUtils.TYPE_*.
|
||||
* Default tab order.
|
||||
*/
|
||||
private final ListView[] mLists = new ListView[ADAPTER_COUNT];
|
||||
public static final int[] DEFAULT_ORDER = { MediaUtils.TYPE_ARTIST, MediaUtils.TYPE_ALBUM, MediaUtils.TYPE_SONG,
|
||||
MediaUtils.TYPE_PLAYLIST, MediaUtils.TYPE_GENRE, MediaUtils.TYPE_FILE };
|
||||
/**
|
||||
* The user-chosen tab order.
|
||||
*/
|
||||
int[] mTabOrder;
|
||||
/**
|
||||
* The number of visible tabs.
|
||||
*/
|
||||
private int mTabCount;
|
||||
/**
|
||||
* The ListView for each adapter. Each index corresponds to that list's
|
||||
* MediaUtils id.
|
||||
*/
|
||||
private final ListView[] mLists = new ListView[MAX_ADAPTER_COUNT];
|
||||
/**
|
||||
* The adapters. Each index corresponds to that adapter's MediaUtils id.
|
||||
*/
|
||||
public LibraryAdapter[] mAdapters = new LibraryAdapter[MAX_ADAPTER_COUNT];
|
||||
/**
|
||||
* Whether the adapter corresponding to each index has stale data.
|
||||
*/
|
||||
private final boolean[] mRequeryNeeded = new boolean[ADAPTER_COUNT];
|
||||
private final boolean[] mRequeryNeeded = new boolean[MAX_ADAPTER_COUNT];
|
||||
/**
|
||||
* Each adapter, in the same order as MediaUtils.TYPE_*.
|
||||
* The artist adapter instance, also stored at mAdapters[MediaUtils.TYPE_ARTIST].
|
||||
*/
|
||||
public final LibraryAdapter[] mAdapters = new LibraryAdapter[ADAPTER_COUNT];
|
||||
private MediaAdapter mArtistAdapter;
|
||||
/**
|
||||
* The album adapter instance, also stored at mAdapters[1].
|
||||
* The album adapter instance, also stored at mAdapters[MediaUtils.TYPE_ALBUM].
|
||||
*/
|
||||
private MediaAdapter mAlbumAdapter;
|
||||
/**
|
||||
* The song adapter instance, also stored at mAdapters[2].
|
||||
* The song adapter instance, also stored at mAdapters[MediaUtils.TYPE_SONG].
|
||||
*/
|
||||
private MediaAdapter mSongAdapter;
|
||||
/**
|
||||
* The playlist adapter instance, also stored at mAdapters[3].
|
||||
* The playlist adapter instance, also stored at mAdapters[MediaUtils.TYPE_PLAYLIST].
|
||||
*/
|
||||
MediaAdapter mPlaylistAdapter;
|
||||
/**
|
||||
* The file adapter instance, also stored at mAdapters[5].
|
||||
* The genre adapter instance, also stored at mAdapters[MediaUtils.TYPE_GENRE].
|
||||
*/
|
||||
private MediaAdapter mGenreAdapter;
|
||||
/**
|
||||
* The file adapter instance, also stored at mAdapters[MediaUtils.TYPE_FILE].
|
||||
*/
|
||||
private FileSystemAdapter mFilesAdapter;
|
||||
/**
|
||||
@ -125,7 +149,7 @@ public class LibraryPagerAdapter
|
||||
*/
|
||||
private final Handler mUiHandler;
|
||||
/**
|
||||
* A Handler runing on a worker thread.
|
||||
* A Handler running on a worker thread.
|
||||
*/
|
||||
private final Handler mWorkerHandler;
|
||||
/**
|
||||
@ -140,6 +164,14 @@ public class LibraryPagerAdapter
|
||||
* The current filter text, or null if none.
|
||||
*/
|
||||
private String mFilter;
|
||||
/**
|
||||
* The position of the songs page, or -1 if it is hidden.
|
||||
*/
|
||||
private int mSongsPosition = -1;
|
||||
/**
|
||||
* The position of the albums page, or -1 if it is hidden.
|
||||
*/
|
||||
private int mAlbumsPosition = -1;
|
||||
|
||||
private final ContentObserver mPlaylistObserver = new ContentObserver(null) {
|
||||
@Override
|
||||
@ -167,10 +199,85 @@ public class LibraryPagerAdapter
|
||||
activity.getContentResolver().registerContentObserver(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, true, mPlaylistObserver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the tab order from SharedPreferences.
|
||||
*
|
||||
* @return True if order has changed.
|
||||
*/
|
||||
public boolean loadTabOrder()
|
||||
{
|
||||
String in = PlaybackService.getSettings(mActivity).getString("tab_order", null);
|
||||
int[] order;
|
||||
int count;
|
||||
if (in == null || in.length() != MAX_ADAPTER_COUNT) {
|
||||
order = DEFAULT_ORDER;
|
||||
count = MAX_ADAPTER_COUNT;
|
||||
} else {
|
||||
char[] chars = in.toCharArray();
|
||||
order = new int[MAX_ADAPTER_COUNT];
|
||||
count = 0;
|
||||
for (int i = 0; i != MAX_ADAPTER_COUNT; ++i) {
|
||||
char v = chars[i];
|
||||
if (v >= 128) {
|
||||
v -= 128;
|
||||
if (v >= MediaUtils.TYPE_COUNT) {
|
||||
// invalid media type; use default order
|
||||
order = DEFAULT_ORDER;
|
||||
count = MAX_ADAPTER_COUNT;
|
||||
break;
|
||||
}
|
||||
order[count++] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count != mTabCount || !Arrays.equals(order, mTabOrder)) {
|
||||
mTabOrder = order;
|
||||
mTabCount = count;
|
||||
notifyDataSetChanged();
|
||||
computeExpansions();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether adapters should be expandable from the visibility of
|
||||
* the adapters each expands to. Also updates mSongsPosition/mAlbumsPositions.
|
||||
*/
|
||||
public void computeExpansions()
|
||||
{
|
||||
int[] order = mTabOrder;
|
||||
int songsPosition = -1;
|
||||
int albumsPosition = -1;
|
||||
for (int i = mTabCount; --i != -1; ) {
|
||||
switch (order[i]) {
|
||||
case MediaUtils.TYPE_ALBUM:
|
||||
albumsPosition = i;
|
||||
break;
|
||||
case MediaUtils.TYPE_SONG:
|
||||
songsPosition = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mArtistAdapter != null)
|
||||
mArtistAdapter.setExpandable(songsPosition != -1 || albumsPosition != -1);
|
||||
if (mAlbumAdapter != null)
|
||||
mAlbumAdapter.setExpandable(songsPosition != -1);
|
||||
if (mGenreAdapter != null)
|
||||
mGenreAdapter.setExpandable(songsPosition != -1);
|
||||
|
||||
mSongsPosition = songsPosition;
|
||||
mAlbumsPosition = albumsPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position)
|
||||
{
|
||||
ListView view = mLists[position];
|
||||
int type = mTabOrder[position];
|
||||
ListView view = mLists[type];
|
||||
|
||||
if (view == null) {
|
||||
LibraryActivity activity = mActivity;
|
||||
@ -178,75 +285,91 @@ public class LibraryPagerAdapter
|
||||
LibraryAdapter adapter;
|
||||
TextView header = null;
|
||||
|
||||
switch (position) {
|
||||
case 0:
|
||||
adapter = new MediaAdapter(activity, MediaUtils.TYPE_ARTIST, null);
|
||||
switch (type) {
|
||||
case MediaUtils.TYPE_ARTIST:
|
||||
adapter = mArtistAdapter = new MediaAdapter(activity, MediaUtils.TYPE_ARTIST, null);
|
||||
mArtistAdapter.setExpandable(mSongsPosition != -1 || mAlbumsPosition != -1);
|
||||
mArtistHeader = header = (TextView)inflater.inflate(R.layout.library_row, null);
|
||||
break;
|
||||
case 1:
|
||||
case MediaUtils.TYPE_ALBUM:
|
||||
adapter = mAlbumAdapter = new MediaAdapter(activity, MediaUtils.TYPE_ALBUM, mPendingAlbumLimiter);
|
||||
mAlbumAdapter.setExpandable(mSongsPosition != -1);
|
||||
mPendingAlbumLimiter = null;
|
||||
mAlbumHeader = header = (TextView)inflater.inflate(R.layout.library_row, null);
|
||||
break;
|
||||
case 2:
|
||||
case MediaUtils.TYPE_SONG:
|
||||
adapter = mSongAdapter = new MediaAdapter(activity, MediaUtils.TYPE_SONG, mPendingSongLimiter);
|
||||
mPendingSongLimiter = null;
|
||||
mSongHeader = header = (TextView)inflater.inflate(R.layout.library_row, null);
|
||||
break;
|
||||
case 3:
|
||||
case MediaUtils.TYPE_PLAYLIST:
|
||||
adapter = mPlaylistAdapter = new MediaAdapter(activity, MediaUtils.TYPE_PLAYLIST, null);
|
||||
break;
|
||||
case 4:
|
||||
adapter = new MediaAdapter(activity, MediaUtils.TYPE_GENRE, null);
|
||||
case MediaUtils.TYPE_GENRE:
|
||||
adapter = mGenreAdapter = new MediaAdapter(activity, MediaUtils.TYPE_GENRE, null);
|
||||
mGenreAdapter.setExpandable(mSongsPosition != -1);
|
||||
break;
|
||||
case 5:
|
||||
case MediaUtils.TYPE_FILE:
|
||||
adapter = mFilesAdapter = new FileSystemAdapter(activity, mPendingFileLimiter);
|
||||
mPendingFileLimiter = null;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid position: " + position);
|
||||
throw new IllegalArgumentException("Invalid media type: " + type);
|
||||
}
|
||||
|
||||
view = (ListView)inflater.inflate(R.layout.listview, null);
|
||||
view.setOnCreateContextMenuListener(this);
|
||||
view.setOnItemClickListener(this);
|
||||
view.setTag(type);
|
||||
if (header != null) {
|
||||
header.setText(mHeaderText);
|
||||
header.setTag(position + 1);
|
||||
header.setTag(type);
|
||||
view.addHeaderView(header);
|
||||
}
|
||||
view.setAdapter(adapter);
|
||||
if (position != 5)
|
||||
if (type != MediaUtils.TYPE_FILE)
|
||||
loadSortOrder((MediaAdapter)adapter);
|
||||
enableFastScroll(view);
|
||||
adapter.setFilter(mFilter);
|
||||
|
||||
mAdapters[position] = adapter;
|
||||
mLists[position] = view;
|
||||
mRequeryNeeded[position] = true;
|
||||
mAdapters[type] = adapter;
|
||||
mLists[type] = view;
|
||||
mRequeryNeeded[type] = true;
|
||||
}
|
||||
|
||||
requeryIfNeeded(position);
|
||||
requeryIfNeeded(type);
|
||||
container.addView(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPosition(Object item)
|
||||
{
|
||||
int type = (Integer)((ListView)item).getTag();
|
||||
int[] order = mTabOrder;
|
||||
for (int i = mTabCount; --i != -1; ) {
|
||||
if (order[i] == type)
|
||||
return i;
|
||||
}
|
||||
return POSITION_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object)
|
||||
{
|
||||
container.removeView(mLists[position]);
|
||||
container.removeView((View)object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position)
|
||||
{
|
||||
return mActivity.getResources().getText(TITLES[position]);
|
||||
return mActivity.getResources().getText(TITLES[mTabOrder[position]]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
return ADAPTER_COUNT;
|
||||
return mTabCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -258,12 +381,13 @@ public class LibraryPagerAdapter
|
||||
@Override
|
||||
public void setPrimaryItem(ViewGroup container, int position, Object object)
|
||||
{
|
||||
LibraryAdapter adapter = mAdapters[position];
|
||||
if (adapter != mCurrentAdapter) {
|
||||
requeryIfNeeded(position);
|
||||
int type = mTabOrder[position];
|
||||
LibraryAdapter adapter = mAdapters[type];
|
||||
if (position != mCurrentPage || adapter != mCurrentAdapter) {
|
||||
requeryIfNeeded(type);
|
||||
mCurrentAdapter = adapter;
|
||||
mCurrentPage = position;
|
||||
mActivity.onAdapterSelected(adapter);
|
||||
mActivity.onPageChanged(position, adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,9 +412,9 @@ public class LibraryPagerAdapter
|
||||
if (mFilesAdapter != null)
|
||||
out.putSerializable("limiter_files", mFilesAdapter.getLimiter());
|
||||
|
||||
int[] savedPositions = new int[ADAPTER_COUNT];
|
||||
int[] savedPositions = new int[MAX_ADAPTER_COUNT];
|
||||
ListView[] lists = mLists;
|
||||
for (int i = ADAPTER_COUNT; --i != -1; ) {
|
||||
for (int i = MAX_ADAPTER_COUNT; --i != -1; ) {
|
||||
if (lists[i] != null) {
|
||||
savedPositions[i] = lists[i].getFirstVisiblePosition();
|
||||
}
|
||||
@ -350,7 +474,7 @@ public class LibraryPagerAdapter
|
||||
* Update the adapters with the given limiter.
|
||||
*
|
||||
* @param limiter The limiter to set.
|
||||
* @return The tab appropriate for expanding a row.
|
||||
* @return The tab type that should be switched to to expand the row.
|
||||
*/
|
||||
public int setLimiter(Limiter limiter)
|
||||
{
|
||||
@ -365,7 +489,7 @@ public class LibraryPagerAdapter
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
tab = 2;
|
||||
tab = mSongsPosition;
|
||||
break;
|
||||
case MediaUtils.TYPE_ARTIST:
|
||||
if (mAlbumAdapter == null) {
|
||||
@ -382,7 +506,9 @@ public class LibraryPagerAdapter
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
tab = 1;
|
||||
tab = mAlbumsPosition;
|
||||
if (tab == -1)
|
||||
tab = mSongsPosition;
|
||||
break;
|
||||
case MediaUtils.TYPE_GENRE:
|
||||
if (mAlbumAdapter == null) {
|
||||
@ -399,7 +525,7 @@ public class LibraryPagerAdapter
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
tab = 2;
|
||||
tab = mSongsPosition;
|
||||
break;
|
||||
case MediaUtils.TYPE_FILE:
|
||||
if (mFilesAdapter == null) {
|
||||
@ -408,7 +534,7 @@ public class LibraryPagerAdapter
|
||||
mFilesAdapter.setLimiter(limiter);
|
||||
requestRequery(mFilesAdapter);
|
||||
}
|
||||
tab = 5;
|
||||
tab = -1;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported limiter type: " + limiter.type);
|
||||
@ -461,7 +587,7 @@ public class LibraryPagerAdapter
|
||||
switch (message.what) {
|
||||
case MSG_RUN_QUERY: {
|
||||
LibraryAdapter adapter = (LibraryAdapter)message.obj;
|
||||
int index = adapter.getMediaType() - 1;
|
||||
int index = adapter.getMediaType();
|
||||
Handler handler = mUiHandler;
|
||||
handler.sendMessage(handler.obtainMessage(MSG_COMMIT_QUERY, index, 0, adapter.query()));
|
||||
break;
|
||||
@ -508,7 +634,7 @@ public class LibraryPagerAdapter
|
||||
if (adapter == mCurrentAdapter) {
|
||||
postRunQuery(adapter);
|
||||
} else {
|
||||
mRequeryNeeded[adapter.getMediaType() - 1] = true;
|
||||
mRequeryNeeded[adapter.getMediaType()] = true;
|
||||
// Clear the data for non-visible adapters (so we don't show the old
|
||||
// data briefly when we later switch to that adapter)
|
||||
adapter.clear();
|
||||
@ -534,21 +660,21 @@ public class LibraryPagerAdapter
|
||||
*/
|
||||
private void postRunQuery(LibraryAdapter adapter)
|
||||
{
|
||||
mRequeryNeeded[adapter.getMediaType() - 1] = false;
|
||||
mRequeryNeeded[adapter.getMediaType()] = false;
|
||||
Handler handler = mWorkerHandler;
|
||||
handler.removeMessages(MSG_RUN_QUERY, adapter);
|
||||
handler.sendMessage(handler.obtainMessage(MSG_RUN_QUERY, adapter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Requery the adapter at the given position if it exists and needs a requery.
|
||||
* Requery the adapter of the given type if it exists and needs a requery.
|
||||
*
|
||||
* @param position An index in mAdapters.
|
||||
* @param type One of MediaUtils.TYPE_*
|
||||
*/
|
||||
private void requeryIfNeeded(int position)
|
||||
private void requeryIfNeeded(int type)
|
||||
{
|
||||
LibraryAdapter adapter = mAdapters[position];
|
||||
if (adapter != null && mRequeryNeeded[position]) {
|
||||
LibraryAdapter adapter = mAdapters[type];
|
||||
if (adapter != null && mRequeryNeeded[type]) {
|
||||
postRunQuery(adapter);
|
||||
}
|
||||
}
|
||||
@ -598,7 +724,7 @@ public class LibraryPagerAdapter
|
||||
|
||||
// Force a new FastScroller to be created so the scroll sections
|
||||
// are updated.
|
||||
ListView view = mLists[mCurrentPage];
|
||||
ListView view = mLists[mTabOrder[mCurrentPage]];
|
||||
view.setFastScrollEnabled(false);
|
||||
enableFastScroll(view);
|
||||
|
||||
|
@ -36,8 +36,9 @@ import android.text.style.ForegroundColorSpan;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.SectionIndexer;
|
||||
import android.widget.TextView;
|
||||
import java.util.regex.Pattern;
|
||||
@ -54,7 +55,7 @@ import java.util.regex.Pattern;
|
||||
* See getLimiter and setLimiter for details.
|
||||
*/
|
||||
public class MediaAdapter
|
||||
extends CursorAdapter
|
||||
extends BaseAdapter
|
||||
implements SectionIndexer
|
||||
, LibraryAdapter
|
||||
, View.OnClickListener
|
||||
@ -69,6 +70,10 @@ public class MediaAdapter
|
||||
* A LayoutInflater to use.
|
||||
*/
|
||||
private final LayoutInflater mInflater;
|
||||
/**
|
||||
* The current data.
|
||||
*/
|
||||
private Cursor mCursor;
|
||||
/**
|
||||
* The type of media represented by this adapter. Must be one of the
|
||||
* MediaUtils.FIELD_* constants. Determines which content provider to query for
|
||||
@ -132,9 +137,9 @@ public class MediaAdapter
|
||||
*/
|
||||
private int mSortMode;
|
||||
/**
|
||||
* The layout used for each row.
|
||||
* If true, show the expander button on each row.
|
||||
*/
|
||||
private int mLayout;
|
||||
private boolean mExpandable;
|
||||
|
||||
/**
|
||||
* Construct a MediaAdapter representing the given <code>type</code> of
|
||||
@ -148,8 +153,6 @@ public class MediaAdapter
|
||||
*/
|
||||
public MediaAdapter(LibraryActivity activity, int type, Limiter limiter)
|
||||
{
|
||||
super(activity, null, false);
|
||||
|
||||
mActivity = activity;
|
||||
mType = type;
|
||||
mLimiter = limiter;
|
||||
@ -164,7 +167,6 @@ public class MediaAdapter
|
||||
mSongSort = MediaUtils.DEFAULT_SORT;
|
||||
mSortEntries = new int[] { R.string.name, R.string.number_of_tracks };
|
||||
mSortValues = new String[] { "artist_key %1$s", "number_of_tracks %1$s,artist_key %1$s" };
|
||||
mLayout = R.layout.library_row_expandable;
|
||||
break;
|
||||
case MediaUtils.TYPE_ALBUM:
|
||||
mStore = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;
|
||||
@ -174,7 +176,6 @@ public class MediaAdapter
|
||||
mSongSort = "album_key,track";
|
||||
mSortEntries = new int[] { R.string.name, R.string.artist_album, R.string.year, R.string.number_of_tracks };
|
||||
mSortValues = new String[] { "album_key %1$s", "artist_key %1$s,album_key %1$s", "minyear %1$s,album_key %1$s", "numsongs %1$s,album_key %1$s" };
|
||||
mLayout = R.layout.library_row_expandable;
|
||||
break;
|
||||
case MediaUtils.TYPE_SONG:
|
||||
mStore = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
@ -182,7 +183,6 @@ public class MediaAdapter
|
||||
mFieldKeys = new String[] { MediaStore.Audio.Media.ARTIST_KEY, MediaStore.Audio.Media.ALBUM_KEY, MediaStore.Audio.Media.TITLE_KEY };
|
||||
mSortEntries = new int[] { R.string.name, R.string.artist_album_track, R.string.artist_album_title, R.string.artist_year, R.string.year };
|
||||
mSortValues = new String[] { "title_key %1$s", "artist_key %1$s,album_key %1$s,track %1$s", "artist_key %1$s,album_key %1$s,title_key %1$s", "artist_key %1$s,year %1$s,track %1$s", "year %1$s,title_key %1$s" };
|
||||
mLayout = R.layout.library_row;
|
||||
break;
|
||||
case MediaUtils.TYPE_PLAYLIST:
|
||||
mStore = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
|
||||
@ -190,7 +190,7 @@ public class MediaAdapter
|
||||
mFieldKeys = null;
|
||||
mSortEntries = new int[] { R.string.name, R.string.date_added };
|
||||
mSortValues = new String[] { "name %1$s", "date_added %1$s" };
|
||||
mLayout = R.layout.library_row_expandable;
|
||||
mExpandable = true;
|
||||
break;
|
||||
case MediaUtils.TYPE_GENRE:
|
||||
mStore = MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI;
|
||||
@ -198,7 +198,6 @@ public class MediaAdapter
|
||||
mFieldKeys = null;
|
||||
mSortEntries = new int[] { R.string.name };
|
||||
mSortValues = new String[] { "name %1$s" };
|
||||
mLayout = R.layout.library_row_expandable;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid value for type: " + type);
|
||||
@ -210,6 +209,20 @@ public class MediaAdapter
|
||||
mProjection = new String[] { BaseColumns._ID, mFields[mFields.length - 1], mFields[0] };
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the expander button should be shown in each row.
|
||||
* Defaults to true for playlist adapter and false for all others.
|
||||
*
|
||||
* @param expandable True to show expander, false to hide.
|
||||
*/
|
||||
public void setExpandable(boolean expandable)
|
||||
{
|
||||
if (expandable != mExpandable) {
|
||||
mExpandable = expandable;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFilter(String filter)
|
||||
{
|
||||
@ -359,7 +372,7 @@ public class MediaAdapter
|
||||
String[] fields;
|
||||
Object data;
|
||||
|
||||
Cursor cursor = getCursor();
|
||||
Cursor cursor = mCursor;
|
||||
if (cursor == null)
|
||||
return null;
|
||||
for (int i = 0, count = cursor.getCount(); i != count; ++i) {
|
||||
@ -388,11 +401,24 @@ public class MediaAdapter
|
||||
return new Limiter(mType, fields, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Set a new cursor for this adapter. The old cursor will be closed.
|
||||
*
|
||||
* @param cursor The new cursor.
|
||||
*/
|
||||
public void changeCursor(Cursor cursor)
|
||||
{
|
||||
super.changeCursor(cursor);
|
||||
Cursor old = mCursor;
|
||||
mCursor = cursor;
|
||||
if (cursor == null) {
|
||||
notifyDataSetInvalidated();
|
||||
} else {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
mIndexer.setCursor(cursor);
|
||||
if (old != null) {
|
||||
old.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -432,13 +458,36 @@ public class MediaAdapter
|
||||
public ImageView arrow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the values in the given view.
|
||||
*/
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor)
|
||||
public View getView(int position, View view, ViewGroup parent)
|
||||
{
|
||||
ViewHolder holder = (ViewHolder)view.getTag();
|
||||
ViewHolder holder;
|
||||
|
||||
if (view == null || mExpandable != view instanceof LinearLayout) {
|
||||
// We must create a new view if we're not given a recycle view or
|
||||
// if the recycle view has the wrong layout.
|
||||
|
||||
int layout = mExpandable ? R.layout.library_row_expandable : R.layout.library_row;
|
||||
view = mInflater.inflate(layout, null);
|
||||
holder = new ViewHolder();
|
||||
view.setTag(holder);
|
||||
|
||||
if (mExpandable) {
|
||||
holder.text = (TextView)view.findViewById(R.id.text);
|
||||
holder.arrow = (ImageView)view.findViewById(R.id.arrow);
|
||||
holder.arrow.setOnClickListener(this);
|
||||
} else {
|
||||
holder.text = (TextView)view;
|
||||
view.setLongClickable(true);
|
||||
}
|
||||
|
||||
holder.text.setOnClickListener(this);
|
||||
} else {
|
||||
holder = (ViewHolder)view.getTag();
|
||||
}
|
||||
|
||||
Cursor cursor = mCursor;
|
||||
cursor.moveToPosition(position);
|
||||
holder.id = cursor.getLong(0);
|
||||
if (mFields.length > 1) {
|
||||
String line1 = cursor.getString(1);
|
||||
@ -454,29 +503,7 @@ public class MediaAdapter
|
||||
holder.text.setText(title);
|
||||
holder.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new view.
|
||||
*/
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent)
|
||||
{
|
||||
int layout = mLayout;
|
||||
View view = mInflater.inflate(layout, null);
|
||||
ViewHolder holder = new ViewHolder();
|
||||
view.setTag(holder);
|
||||
|
||||
if (layout == R.layout.library_row_expandable) {
|
||||
holder.text = (TextView)view.findViewById(R.id.text);
|
||||
holder.arrow = (ImageView)view.findViewById(R.id.arrow);
|
||||
holder.arrow.setOnClickListener(this);
|
||||
} else {
|
||||
holder.text = (TextView)view;
|
||||
view.setLongClickable(true);
|
||||
}
|
||||
|
||||
holder.text.setOnClickListener(this);
|
||||
return view;
|
||||
}
|
||||
|
||||
@ -546,7 +573,7 @@ public class MediaAdapter
|
||||
intent.putExtra(LibraryAdapter.DATA_TYPE, mType);
|
||||
intent.putExtra(LibraryAdapter.DATA_ID, holder.id);
|
||||
intent.putExtra(LibraryAdapter.DATA_TITLE, holder.title);
|
||||
intent.putExtra(LibraryAdapter.DATA_EXPANDABLE, mType != MediaUtils.TYPE_SONG);
|
||||
intent.putExtra(LibraryAdapter.DATA_EXPANDABLE, mExpandable);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@ -554,7 +581,7 @@ public class MediaAdapter
|
||||
public void onClick(View view)
|
||||
{
|
||||
int id = view.getId();
|
||||
if (mLayout == R.layout.library_row_expandable)
|
||||
if (mExpandable)
|
||||
view = (View)view.getParent();
|
||||
Intent intent = createData(view);
|
||||
if (id == R.id.arrow) {
|
||||
@ -563,4 +590,35 @@ public class MediaAdapter
|
||||
mActivity.onItemClicked(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
Cursor cursor = mCursor;
|
||||
if (cursor == null)
|
||||
return 0;
|
||||
return cursor.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position)
|
||||
{
|
||||
Cursor cursor = mCursor;
|
||||
if (cursor == null)
|
||||
return 0;
|
||||
cursor.moveToPosition(position);
|
||||
return cursor.getLong(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -42,32 +42,36 @@ public class MediaUtils {
|
||||
/**
|
||||
* A special invalid media type.
|
||||
*/
|
||||
public static final int TYPE_INVALID = 0;
|
||||
public static final int TYPE_INVALID = -1;
|
||||
/**
|
||||
* Type indicating an id represents an artist.
|
||||
*/
|
||||
public static final int TYPE_ARTIST = 1;
|
||||
public static final int TYPE_ARTIST = 0;
|
||||
/**
|
||||
* Type indicating an id represents an album.
|
||||
*/
|
||||
public static final int TYPE_ALBUM = 2;
|
||||
public static final int TYPE_ALBUM = 1;
|
||||
/**
|
||||
* Type indicating an id represents a song.
|
||||
*/
|
||||
public static final int TYPE_SONG = 3;
|
||||
public static final int TYPE_SONG = 2;
|
||||
/**
|
||||
* Type indicating an id represents a playlist.
|
||||
*/
|
||||
public static final int TYPE_PLAYLIST = 4;
|
||||
public static final int TYPE_PLAYLIST = 3;
|
||||
/**
|
||||
* Type indicating ids represent genres.
|
||||
*/
|
||||
public static final int TYPE_GENRE = 5;
|
||||
public static final int TYPE_GENRE = 4;
|
||||
/**
|
||||
* Special type for files and folders. Most methods do not accept this type
|
||||
* since files have no MediaStore id and require special handling.
|
||||
*/
|
||||
public static final int TYPE_FILE = 6;
|
||||
public static final int TYPE_FILE = 5;
|
||||
/**
|
||||
* The number of different valid media types.
|
||||
*/
|
||||
public static final int TYPE_COUNT = 6;
|
||||
|
||||
/**
|
||||
* The default sort order for media queries. First artist, then album, then
|
||||
|
@ -97,7 +97,7 @@ public class PlaylistActivity extends Activity
|
||||
|
||||
setContentView(R.layout.playlist_activity);
|
||||
|
||||
DragListView view = (DragListView)findViewById(R.id.playlist);
|
||||
DragListView view = (DragListView)findViewById(R.id.list);
|
||||
view.setOnItemClickListener(this);
|
||||
view.setOnCreateContextMenuListener(this);
|
||||
mListView = view;
|
||||
@ -204,11 +204,12 @@ public class PlaylistActivity extends Activity
|
||||
{
|
||||
int itemId = item.getItemId();
|
||||
Intent intent = item.getIntent();
|
||||
int pos = intent.getIntExtra("position", -1);
|
||||
|
||||
if (itemId == MENU_REMOVE) {
|
||||
mAdapter.remove(intent.getLongExtra("id", -1));
|
||||
mAdapter.remove(pos);
|
||||
} else {
|
||||
performAction(itemId, intent.getIntExtra("position", -1), intent.getLongExtra("audioId", -1));
|
||||
performAction(itemId, pos, intent.getLongExtra("audioId", -1));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -42,7 +42,7 @@ import android.widget.TextView;
|
||||
/**
|
||||
* CursorAdapter backed by MediaStore playlists.
|
||||
*/
|
||||
public class PlaylistAdapter extends CursorAdapter implements Handler.Callback {
|
||||
public class PlaylistAdapter extends CursorAdapter implements Handler.Callback, DragListView.DragAdapter {
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
MediaStore.Audio.Playlists.Members._ID,
|
||||
MediaStore.Audio.Playlists.Members.TITLE,
|
||||
@ -162,12 +162,7 @@ public class PlaylistAdapter extends CursorAdapter implements Handler.Callback {
|
||||
return query.runQuery(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a song to a new position.
|
||||
*
|
||||
* @param from The old position.
|
||||
* @param to The new position.
|
||||
*/
|
||||
@Override
|
||||
public void move(int from, int to)
|
||||
{
|
||||
if (from == to)
|
||||
@ -221,16 +216,12 @@ public class PlaylistAdapter extends CursorAdapter implements Handler.Callback {
|
||||
changeCursor(runQuery(resolver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the song with the given id.
|
||||
*
|
||||
* @param id The MediaStore id of the row to remove.
|
||||
*/
|
||||
public void remove(long id)
|
||||
@Override
|
||||
public void remove(int position)
|
||||
{
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", mPlaylistId);
|
||||
resolver.delete(ContentUris.withAppendedId(uri, id), null, null);
|
||||
resolver.delete(ContentUris.withAppendedId(uri, getItemId(position)), null, null);
|
||||
changeCursor(runQuery(resolver));
|
||||
}
|
||||
}
|
||||
|
156
src/org/kreed/vanilla/TabOrderActivity.java
Normal file
156
src/org/kreed/vanilla/TabOrderActivity.java
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.kreed.vanilla;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
|
||||
/**
|
||||
* The preferences activity in which one can change application preferences.
|
||||
*/
|
||||
public class TabOrderActivity extends Activity implements View.OnClickListener, OnItemClickListener {
|
||||
private TabOrderAdapter mAdapter;
|
||||
private DragListView mList;
|
||||
|
||||
/**
|
||||
* Initialize the activity, loading the preference specifications.
|
||||
*/
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(R.string.tabs);
|
||||
setContentView(R.layout.tab_order);
|
||||
|
||||
mAdapter = new TabOrderAdapter(this);
|
||||
DragListView list = (DragListView)findViewById(R.id.list);
|
||||
list.setAdapter(mAdapter);
|
||||
list.setEditable(true);
|
||||
list.setOnItemClickListener(this);
|
||||
mList = list;
|
||||
load();
|
||||
|
||||
findViewById(R.id.done).setOnClickListener(this);
|
||||
findViewById(R.id.restore_default).setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view)
|
||||
{
|
||||
switch (view.getId()) {
|
||||
case R.id.done:
|
||||
finish();
|
||||
break;
|
||||
case R.id.restore_default:
|
||||
restoreDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the default tab order and visibility.
|
||||
*/
|
||||
public void restoreDefault()
|
||||
{
|
||||
android.util.Log.i("VanillaMusic", "restore default");
|
||||
mAdapter.setTabIds(LibraryPagerAdapter.DEFAULT_ORDER.clone());
|
||||
DragListView list = mList;
|
||||
for (int i = 0; i != LibraryPagerAdapter.MAX_ADAPTER_COUNT; ++i) {
|
||||
list.setItemChecked(i, true);
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save tab order and visibility to SharedPreferences as a string.
|
||||
*/
|
||||
public void save()
|
||||
{
|
||||
int[] ids = mAdapter.getTabIds();
|
||||
DragListView list = mList;
|
||||
char[] out = new char[LibraryPagerAdapter.MAX_ADAPTER_COUNT];
|
||||
for (int i = 0; i != LibraryPagerAdapter.MAX_ADAPTER_COUNT; ++i) {
|
||||
out[i] = (char)(list.isItemChecked(i) ? 128 + ids[i] : 127 - ids[i]);
|
||||
}
|
||||
|
||||
SharedPreferences.Editor editor = PlaybackService.getSettings(this).edit();
|
||||
editor.putString("tab_order", new String(out));
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load tab order settings from SharedPreferences and apply it to the
|
||||
* activity.
|
||||
*/
|
||||
public void load()
|
||||
{
|
||||
String in = PlaybackService.getSettings(this).getString("tab_order", null);
|
||||
if (in != null && in.length() == LibraryPagerAdapter.MAX_ADAPTER_COUNT) {
|
||||
char[] chars = in.toCharArray();
|
||||
int[] ids = new int[LibraryPagerAdapter.MAX_ADAPTER_COUNT];
|
||||
for (int i = 0; i != LibraryPagerAdapter.MAX_ADAPTER_COUNT; ++i) {
|
||||
int v = chars[i];
|
||||
v = v < 128 ? -(v - 127) : v - 128;
|
||||
if (v >= MediaUtils.TYPE_COUNT) {
|
||||
ids = null;
|
||||
break;
|
||||
}
|
||||
ids[i] = v;
|
||||
}
|
||||
|
||||
if (ids != null) {
|
||||
mAdapter.setTabIds(ids);
|
||||
DragListView list = mList;
|
||||
for (int i = 0; i != LibraryPagerAdapter.MAX_ADAPTER_COUNT; ++i) {
|
||||
list.setItemChecked(i, chars[i] >= 128);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
restoreDefault();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
|
||||
{
|
||||
save();
|
||||
}
|
||||
}
|
130
src/org/kreed/vanilla/TabOrderAdapter.java
Normal file
130
src/org/kreed/vanilla/TabOrderAdapter.java
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Christopher Eby <kreed@kreed.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.kreed.vanilla;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
/**
|
||||
* CursorAdapter backed by MediaStore playlists.
|
||||
*/
|
||||
public class TabOrderAdapter extends BaseAdapter implements DragListView.DragAdapter {
|
||||
private final TabOrderActivity mActivity;
|
||||
private final LayoutInflater mInflater;
|
||||
private int[] mTabIds;
|
||||
|
||||
/**
|
||||
* Create a tab order adapter.
|
||||
*
|
||||
* @param activity The activity that will own this adapter. The activity
|
||||
* will be notified when items have been moved.
|
||||
*/
|
||||
public TabOrderAdapter(TabOrderActivity activity)
|
||||
{
|
||||
mActivity = activity;
|
||||
mInflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the array containing the order of tab ids.
|
||||
*/
|
||||
public void setTabIds(int[] ids)
|
||||
{
|
||||
mTabIds = ids;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array containing the order of tab ids. Do not modify the array.
|
||||
*/
|
||||
public int[] getTabIds()
|
||||
{
|
||||
return mTabIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(int from, int to)
|
||||
{
|
||||
if (from == to)
|
||||
return;
|
||||
|
||||
int[] ids = mTabIds;
|
||||
int tempId = ids[from];
|
||||
|
||||
if (from > to) {
|
||||
System.arraycopy(ids, to, ids, to + 1, from - to);
|
||||
} else {
|
||||
System.arraycopy(ids, from + 1, ids, from, to - from);
|
||||
}
|
||||
|
||||
ids[to] = tempId;
|
||||
notifyDataSetChanged();
|
||||
mActivity.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(int position)
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
return LibraryPagerAdapter.MAX_ADAPTER_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position)
|
||||
{
|
||||
return mTabIds[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convert, ViewGroup parent)
|
||||
{
|
||||
DragTextView text;
|
||||
if (convert == null) {
|
||||
text = (DragTextView)mInflater.inflate(R.layout.tab_order_row, null);
|
||||
} else {
|
||||
text = (DragTextView)convert;
|
||||
}
|
||||
text.setText(LibraryPagerAdapter.TITLES[mTabIds[position]]);
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
47
src/org/kreed/vanilla/TabOrderPreference.java
Normal file
47
src/org/kreed/vanilla/TabOrderPreference.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.kreed.vanilla;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.preference.Preference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* A preference that opens the tab order selector.
|
||||
*/
|
||||
public class TabOrderPreference extends Preference {
|
||||
public TabOrderPreference(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
setTitle(R.string.tabs);
|
||||
setSummary(R.string.customize_tab_order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
Context context = getContext();
|
||||
context.startActivity(new Intent(context, TabOrderActivity.class));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user