From 64a3b588a34c0158a5d7521697396d48ea833fb3 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Sat, 16 May 2015 16:00:00 -0700 Subject: #453 Move to using a RecyclerView for directories --- app/src/main/res/layout/album_cell_item.xml | 5 +++-- app/src/main/res/layout/album_list_item.xml | 2 +- app/src/main/res/layout/grid_view.xml | 14 -------------- app/src/main/res/layout/select_album.xml | 5 ++--- app/src/main/res/layout/song_list_item.xml | 2 +- app/src/main/res/layout/unscrollable_grid_view.xml | 11 ----------- 6 files changed, 7 insertions(+), 32 deletions(-) delete mode 100644 app/src/main/res/layout/grid_view.xml delete mode 100644 app/src/main/res/layout/unscrollable_grid_view.xml (limited to 'app/src/main/res/layout') diff --git a/app/src/main/res/layout/album_cell_item.xml b/app/src/main/res/layout/album_cell_item.xml index 3f708e63..46e2b1a6 100644 --- a/app/src/main/res/layout/album_cell_item.xml +++ b/app/src/main/res/layout/album_cell_item.xml @@ -2,7 +2,8 @@ + android:layout_height="match_parent" + android:background="@drawable/abc_item_background_holo_light"> - \ No newline at end of file diff --git a/app/src/main/res/layout/select_album.xml b/app/src/main/res/layout/select_album.xml index bbdf0e54..cacbc560 100644 --- a/app/src/main/res/layout/select_album.xml +++ b/app/src/main/res/layout/select_album.xml @@ -17,12 +17,11 @@ - + android:scrollbars="vertical"/> \ No newline at end of file diff --git a/app/src/main/res/layout/song_list_item.xml b/app/src/main/res/layout/song_list_item.xml index 86f77869..26c89b2b 100644 --- a/app/src/main/res/layout/song_list_item.xml +++ b/app/src/main/res/layout/song_list_item.xml @@ -117,7 +117,7 @@ - \ No newline at end of file -- cgit v1.2.3 From f701c7d9ad5a4bd691de7dc3cf47b1967b60b516 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 22 May 2015 17:03:39 -0700 Subject: Fix item selection animation --- .../daneren2005/dsub/adapter/EntryGridAdapter.java | 9 +- .../github/daneren2005/dsub/view/AlbumView.java | 3 - .../daneren2005/dsub/view/HeaderGridView.java | 836 --------------------- app/src/main/res/layout/song_list_item.xml | 3 +- 4 files changed, 7 insertions(+), 844 deletions(-) delete mode 100644 app/src/main/java/github/daneren2005/dsub/view/HeaderGridView.java (limited to 'app/src/main/res/layout') diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java index 6de7ce33..80d1ade9 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java @@ -17,6 +17,7 @@ package github.daneren2005.dsub.adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -87,13 +88,13 @@ public class EntryGridAdapter extends RecyclerView.Adapter { if(viewType != VIEW_TYPE_HEADER && updateView != null) { final UpdateView view = updateView; - updateView.setOnClickListener(new View.OnClickListener() { + updateView.getChildAt(0).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Entry entry = getEntryForView(view); - if (view.isCheckable() && v instanceof SongView) { - SongView songView = (SongView) v; + if (view.isCheckable() && view instanceof SongView) { + SongView songView = (SongView) view; if (selected.contains(entry)) { selected.remove(entry); @@ -107,7 +108,7 @@ public class EntryGridAdapter extends RecyclerView.Adapter { } } }); - updateView.setOnLongClickListener(new View.OnLongClickListener() { + updateView.getChildAt(0).setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { Entry entry = getEntryForView(view); diff --git a/app/src/main/java/github/daneren2005/dsub/view/AlbumView.java b/app/src/main/java/github/daneren2005/dsub/view/AlbumView.java index 2eb30037..69f2ef13 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/AlbumView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/AlbumView.java @@ -66,9 +66,6 @@ public class AlbumView extends UpdateView { starButton = (ImageButton) findViewById(R.id.album_star); starButton.setFocusable(false); moreButton = (ImageView) findViewById(R.id.more_button); - - setClickable(true); - setLongClickable(true); } public void setShowArtist(boolean showArtist) { diff --git a/app/src/main/java/github/daneren2005/dsub/view/HeaderGridView.java b/app/src/main/java/github/daneren2005/dsub/view/HeaderGridView.java deleted file mode 100644 index 8a82f353..00000000 --- a/app/src/main/java/github/daneren2005/dsub/view/HeaderGridView.java +++ /dev/null @@ -1,836 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package github.daneren2005.dsub.view; - -import android.annotation.TargetApi; -import android.content.Context; -import android.database.DataSetObservable; -import android.database.DataSetObserver; -import android.os.Build; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.*; - -import java.lang.reflect.Field; -import java.util.ArrayList; - -/** - * A {@link GridView} that supports adding header rows in a - * very similar way to {@link android.widget.ListView}. - * See {@link HeaderGridView#addHeaderView(View, Object, boolean)} - * See {@link HeaderGridView#addFooterView(View, Object, boolean)} - */ -public class HeaderGridView extends GridView { - private static final String TAG = HeaderGridView.class.getSimpleName(); - public static boolean DEBUG = false; - - /** - * A class that represents a fixed view in a list, for example a header at the top - * or a footer at the bottom. - */ - private static class FixedViewInfo { - /** - * The view to add to the grid - */ - public View view; - public ViewGroup viewContainer; - /** - * The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. - */ - public Object data; - /** - * true if the fixed view should be selectable in the grid - */ - public boolean isSelectable; - } - - private int mNumColumns = AUTO_FIT; - private View mViewForMeasureRowHeight = null; - private int mRowHeight = -1; - private static final String LOG_TAG = HeaderGridView.class.getSimpleName(); - - private ArrayList mHeaderViewInfos = new ArrayList(); - private ArrayList mFooterViewInfos = new ArrayList(); - - private void initHeaderGridView() { - } - - public HeaderGridView(Context context) { - super(context); - initHeaderGridView(); - } - - public HeaderGridView(Context context, AttributeSet attrs) { - super(context, attrs); - initHeaderGridView(); - } - - public HeaderGridView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initHeaderGridView(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - ListAdapter adapter = getAdapter(); - if (adapter != null && adapter instanceof HeaderViewGridAdapter) { - ((HeaderViewGridAdapter) adapter).setNumColumns(getNumColumnsCompatible()); - ((HeaderViewGridAdapter) adapter).setRowHeight(getRowHeight()); - } - } - - @Override - public void setClipChildren(boolean clipChildren) { - // Ignore, since the header rows depend on not being clipped - } - - /** - * Do not call this method unless you know how it works. - * - * @param clipChildren - */ - public void setClipChildrenSupper(boolean clipChildren) { - super.setClipChildren(false); - } - - /** - * Add a fixed view to appear at the top of the grid. If addHeaderView is - * called more than once, the views will appear in the order they were - * added. Views added using this call can take focus if they want. - *

- * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap - * the supplied cursor with one that will also account for header views. - * - * @param v The view to add. - */ - public void addHeaderView(View v) { - addHeaderView(v, null, true); - } - - /** - * Add a fixed view to appear at the top of the grid. If addHeaderView is - * called more than once, the views will appear in the order they were - * added. Views added using this call can take focus if they want. - *

- * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap - * the supplied cursor with one that will also account for header views. - * - * @param v The view to add. - * @param data Data to associate with this view - * @param isSelectable whether the item is selectable - */ - public void addHeaderView(View v, Object data, boolean isSelectable) { - ListAdapter adapter = getAdapter(); - if (adapter != null && !(adapter instanceof HeaderViewGridAdapter)) { - throw new IllegalStateException( - "Cannot add header view to grid -- setAdapter has already been called."); - } - - ViewGroup.LayoutParams lyp = v.getLayoutParams(); - - FixedViewInfo info = new FixedViewInfo(); - FrameLayout fl = new FullWidthFixedViewLayout(getContext()); - - if (lyp != null) { - v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height)); - fl.setLayoutParams(new AbsListView.LayoutParams(lyp.width, lyp.height)); - } - fl.addView(v); - info.view = v; - info.viewContainer = fl; - info.data = data; - info.isSelectable = isSelectable; - mHeaderViewInfos.add(info); - // in the case of re-adding a header view, or adding one later on, - // we need to notify the observer - if (adapter != null) { - ((HeaderViewGridAdapter) adapter).notifyDataSetChanged(); - } - } - - public void addFooterView(View v) { - addFooterView(v, null, true); - } - - public void addFooterView(View v, Object data, boolean isSelectable) { - ListAdapter mAdapter = getAdapter(); - if (mAdapter != null && !(mAdapter instanceof HeaderViewGridAdapter)) { - throw new IllegalStateException( - "Cannot add header view to grid -- setAdapter has already been called."); - } - - ViewGroup.LayoutParams lyp = v.getLayoutParams(); - - FixedViewInfo info = new FixedViewInfo(); - FrameLayout fl = new FullWidthFixedViewLayout(getContext()); - - if (lyp != null) { - v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height)); - fl.setLayoutParams(new AbsListView.LayoutParams(lyp.width, lyp.height)); - } - fl.addView(v); - info.view = v; - info.viewContainer = fl; - info.data = data; - info.isSelectable = isSelectable; - mFooterViewInfos.add(info); - - if (mAdapter != null) { - ((HeaderViewGridAdapter) mAdapter).notifyDataSetChanged(); - } - } - - public int getHeaderViewCount() { - return mHeaderViewInfos.size(); - } - - public int getFooterViewCount() { - return mFooterViewInfos.size(); - } - - /** - * Removes a previously-added header view. - * - * @param v The view to remove - * @return true if the view was removed, false if the view was not a header - * view - */ - public boolean removeHeaderView(View v) { - if (mHeaderViewInfos.size() > 0) { - boolean result = false; - ListAdapter adapter = getAdapter(); - if (adapter != null && ((HeaderViewGridAdapter) adapter).removeHeader(v)) { - result = true; - } - removeFixedViewInfo(v, mHeaderViewInfos); - return result; - } - return false; - } - - /** - * Removes a previously-added footer view. - * - * @param v The view to remove - * @return true if the view was removed, false if the view was not a header - * view - */ - public boolean removeFooterView(View v) { - if (mFooterViewInfos.size() > 0) { - boolean result = false; - ListAdapter adapter = getAdapter(); - if (adapter != null && ((HeaderViewGridAdapter) adapter).removeFooter(v)) { - result = true; - } - removeFixedViewInfo(v, mFooterViewInfos); - return result; - } - return false; - } - - private void removeFixedViewInfo(View v, ArrayList where) { - int len = where.size(); - for (int i = 0; i < len; ++i) { - FixedViewInfo info = where.get(i); - if (info.view == v) { - where.remove(i); - break; - } - } - } - - @TargetApi(11) - private int getNumColumnsCompatible() { - if (Build.VERSION.SDK_INT >= 11) { - return super.getNumColumns(); - } else { - try { - Field numColumns = GridView.class.getSuperclass().getDeclaredField("mNumColumns"); - numColumns.setAccessible(true); - return numColumns.getInt(this); - } catch (Exception e) { - if (mNumColumns != -1) { - return mNumColumns; - } else { - return 2; - } - } - } - } - - @TargetApi(16) - private int getColumnWidthCompatible() { - if (Build.VERSION.SDK_INT >= 16) { - return super.getColumnWidth(); - } else { - try { - Field numColumns = getClass().getSuperclass().getDeclaredField("mColumnWidth"); - numColumns.setAccessible(true); - return numColumns.getInt(this); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mViewForMeasureRowHeight = null; - } - - public void invalidateRowHeight() { - mRowHeight = -1; - } - - public int getHeaderHeight(int row) { - if (row >= 0) { - return mHeaderViewInfos.get(row).view.getMeasuredHeight(); - } - - return 0; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public int getVerticalSpacing(){ - int value = 0; - - try { - int currentapiVersion = android.os.Build.VERSION.SDK_INT; - if (currentapiVersion < Build.VERSION_CODES.JELLY_BEAN){ - Field field = this.getClass().getSuperclass().getDeclaredField("mVerticalSpacing"); - field.setAccessible(true); - value = field.getInt(this); - } else{ - value = super.getVerticalSpacing(); - } - - }catch (Exception ex){ - - } - - return value; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public int getHorizontalSpacing(){ - int value = 0; - - try { - int currentapiVersion = android.os.Build.VERSION.SDK_INT; - if (currentapiVersion < Build.VERSION_CODES.JELLY_BEAN){ - Field field = this.getClass().getSuperclass().getDeclaredField("mHorizontalSpacing"); - field.setAccessible(true); - value = field.getInt(this); - } else{ - value = super.getHorizontalSpacing(); - } - - }catch (Exception ex){ - - } - - return value; - } - - public int getRowHeight() { - if (mRowHeight > 0) { - // return mRowHeight; - } - ListAdapter adapter = getAdapter(); - int numColumns = getNumColumnsCompatible(); - - // adapter has not been set or has no views in it; - if (adapter == null || adapter.getCount() <= numColumns * (mHeaderViewInfos.size() + mFooterViewInfos.size()) || numColumns == -1) { - return -1; - } - int mColumnWidth = getColumnWidthCompatible(); - View view = getAdapter().getView(numColumns * mHeaderViewInfos.size(), mViewForMeasureRowHeight, this); - AbsListView.LayoutParams p = (AbsListView.LayoutParams) view.getLayoutParams(); - if (p == null) { - p = new AbsListView.LayoutParams(-1, -2, 0); - view.setLayoutParams(p); - } - int childHeightSpec = getChildMeasureSpec( - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height); - int childWidthSpec = getChildMeasureSpec( - MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width); - view.measure(childWidthSpec, childHeightSpec); - mViewForMeasureRowHeight = view; - mRowHeight = view.getMeasuredHeight(); - return mRowHeight; - } - - @TargetApi(11) - public void tryToScrollToBottomSmoothly() { - int lastPos = getAdapter().getCount() - 1; - if (Build.VERSION.SDK_INT >= 11) { - smoothScrollToPositionFromTop(lastPos, 0); - } else { - setSelection(lastPos); - } - } - - @TargetApi(11) - public void tryToScrollToBottomSmoothly(int duration) { - int lastPos = getAdapter().getCount() - 1; - if (Build.VERSION.SDK_INT >= 11) { - smoothScrollToPositionFromTop(lastPos, 0, duration); - } else { - setSelection(lastPos); - } - } - - @Override - public void setAdapter(ListAdapter adapter) { - if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) { - HeaderViewGridAdapter headerViewGridAdapter = new HeaderViewGridAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); - int numColumns = getNumColumnsCompatible(); - if (numColumns > 1) { - headerViewGridAdapter.setNumColumns(numColumns); - } - headerViewGridAdapter.setRowHeight(getRowHeight()); - super.setAdapter(headerViewGridAdapter); - } else { - super.setAdapter(adapter); - } - } - - /** - * full width - */ - private class FullWidthFixedViewLayout extends FrameLayout { - - public FullWidthFixedViewLayout(Context context) { - super(context); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int realLeft = HeaderGridView.this.getPaddingLeft() + getPaddingLeft(); - // Try to make where it should be, from left, full width - if (realLeft != left) { - offsetLeftAndRight(realLeft - left); - } - super.onLayout(changed, left, top, right, bottom); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int targetWidth = HeaderGridView.this.getMeasuredWidth() - - HeaderGridView.this.getPaddingLeft() - - HeaderGridView.this.getPaddingRight(); - widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth, - MeasureSpec.getMode(widthMeasureSpec)); - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - } - - @Override - public void setNumColumns(int numColumns) { - super.setNumColumns(numColumns); - mNumColumns = numColumns; - ListAdapter adapter = getAdapter(); - if (adapter != null && adapter instanceof HeaderViewGridAdapter) { - ((HeaderViewGridAdapter) adapter).setNumColumns(numColumns); - } - } - - /** - * ListAdapter used when a HeaderGridView has header views. This ListAdapter - * wraps another one and also keeps track of the header views and their - * associated data objects. - *

This is intended as a base class; you will probably not need to - * use this class directly in your own code. - */ - private static class HeaderViewGridAdapter extends BaseAdapter implements WrapperListAdapter, Filterable { - // This is used to notify the container of updates relating to number of columns - // or headers changing, which changes the number of placeholders needed - private final DataSetObservable mDataSetObservable = new DataSetObservable(); - private final ListAdapter mAdapter; - static final ArrayList EMPTY_INFO_LIST = - new ArrayList(); - - // This ArrayList is assumed to NOT be null. - ArrayList mHeaderViewInfos; - ArrayList mFooterViewInfos; - private int mNumColumns = 1; - private int mRowHeight = -1; - boolean mAreAllFixedViewsSelectable; - private final boolean mIsFilterable; - private boolean mCachePlaceHoldView = true; - // From Recycle Bin or calling getView, this a question... - private boolean mCacheFirstHeaderView = false; - - public HeaderViewGridAdapter(ArrayList headerViewInfos, ArrayList footViewInfos, ListAdapter adapter) { - mAdapter = adapter; - mIsFilterable = adapter instanceof Filterable; - if (headerViewInfos == null) { - mHeaderViewInfos = EMPTY_INFO_LIST; - } else { - mHeaderViewInfos = headerViewInfos; - } - - if (footViewInfos == null) { - mFooterViewInfos = EMPTY_INFO_LIST; - } else { - mFooterViewInfos = footViewInfos; - } - mAreAllFixedViewsSelectable = areAllListInfosSelectable(mHeaderViewInfos) - && areAllListInfosSelectable(mFooterViewInfos); - } - - public void setNumColumns(int numColumns) { - if (numColumns < 1) { - return; - } - if (mNumColumns != numColumns) { - mNumColumns = numColumns; - notifyDataSetChanged(); - } - } - - public void setRowHeight(int height) { - mRowHeight = height; - } - - public int getHeadersCount() { - return mHeaderViewInfos.size(); - } - - public int getFootersCount() { - return mFooterViewInfos.size(); - } - - @Override - public boolean isEmpty() { - return (mAdapter == null || mAdapter.isEmpty()) && getHeadersCount() == 0 && getFootersCount() == 0; - } - - private boolean areAllListInfosSelectable(ArrayList infos) { - if (infos != null) { - for (FixedViewInfo info : infos) { - if (!info.isSelectable) { - return false; - } - } - } - return true; - } - - public boolean removeHeader(View v) { - for (int i = 0; i < mHeaderViewInfos.size(); i++) { - FixedViewInfo info = mHeaderViewInfos.get(i); - if (info.view == v) { - mHeaderViewInfos.remove(i); - mAreAllFixedViewsSelectable = - areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos); - mDataSetObservable.notifyChanged(); - return true; - } - } - return false; - } - - public boolean removeFooter(View v) { - for (int i = 0; i < mFooterViewInfos.size(); i++) { - FixedViewInfo info = mFooterViewInfos.get(i); - if (info.view == v) { - mFooterViewInfos.remove(i); - mAreAllFixedViewsSelectable = - areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos); - mDataSetObservable.notifyChanged(); - return true; - } - } - return false; - } - - @Override - public int getCount() { - if (mAdapter != null) { - return (getFootersCount() + getHeadersCount()) * mNumColumns + getAdapterAndPlaceHolderCount(); - } else { - return (getFootersCount() + getHeadersCount()) * mNumColumns; - } - } - - @Override - public boolean areAllItemsEnabled() { - if (mAdapter != null) { - return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled(); - } else { - return true; - } - } - - private int getAdapterAndPlaceHolderCount() { - final int adapterCount = (int) (Math.ceil(1f * mAdapter.getCount() / mNumColumns) * mNumColumns); - return adapterCount; - } - - @Override - public boolean isEnabled(int position) { - // Header (negative positions will throw an IndexOutOfBoundsException) - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (position < numHeadersAndPlaceholders) { - return position % mNumColumns == 0 - && mHeaderViewInfos.get(position / mNumColumns).isSelectable; - } - - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition < adapterCount) { - return adjPosition < mAdapter.getCount() && mAdapter.isEnabled(adjPosition); - } - } - - // Footer (off-limits positions will throw an IndexOutOfBoundsException) - final int footerPosition = adjPosition - adapterCount; - return footerPosition % mNumColumns == 0 - && mFooterViewInfos.get(footerPosition / mNumColumns).isSelectable; - } - - @Override - public Object getItem(int position) { - // Header (negative positions will throw an ArrayIndexOutOfBoundsException) - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (position < numHeadersAndPlaceholders) { - if (position % mNumColumns == 0) { - return mHeaderViewInfos.get(position / mNumColumns).data; - } - return null; - } - - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition < adapterCount) { - if (adjPosition < mAdapter.getCount()) { - return mAdapter.getItem(adjPosition); - } else { - return null; - } - } - } - - // Footer (off-limits positions will throw an IndexOutOfBoundsException) - final int footerPosition = adjPosition - adapterCount; - if (footerPosition % mNumColumns == 0) { - return mFooterViewInfos.get(footerPosition).data; - } else { - return null; - } - } - - @Override - public long getItemId(int position) { - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (mAdapter != null && position >= numHeadersAndPlaceholders) { - int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = mAdapter.getCount(); - if (adjPosition < adapterCount) { - return mAdapter.getItemId(adjPosition); - } - } - return -1; - } - - @Override - public boolean hasStableIds() { - if (mAdapter != null) { - return mAdapter.hasStableIds(); - } - return false; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (DEBUG) { - Log.d(LOG_TAG, String.format("getView: %s, reused: %s", position, convertView == null)); - } - // Header (negative positions will throw an ArrayIndexOutOfBoundsException) - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (position < numHeadersAndPlaceholders) { - View headerViewContainer = mHeaderViewInfos - .get(position / mNumColumns).viewContainer; - if (position % mNumColumns == 0) { - return headerViewContainer; - } else { - if (convertView == null) { - convertView = new View(parent.getContext()); - } - // We need to do this because GridView uses the height of the last item - // in a row to determine the height for the entire row. - convertView.setVisibility(View.INVISIBLE); - convertView.setMinimumHeight(headerViewContainer.getHeight()); - return convertView; - } - } - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition < adapterCount) { - if (adjPosition < mAdapter.getCount()) { - View view = mAdapter.getView(adjPosition, convertView, parent); - return view; - } else { - if (convertView == null) { - convertView = new View(parent.getContext()); - } - convertView.setVisibility(View.INVISIBLE); - convertView.setMinimumHeight(mRowHeight); - return convertView; - } - } - } - // Footer - final int footerPosition = adjPosition - adapterCount; - if (footerPosition < getCount()) { - View footViewContainer = mFooterViewInfos - .get(footerPosition / mNumColumns).viewContainer; - if (position % mNumColumns == 0) { - return footViewContainer; - } else { - if (convertView == null) { - convertView = new View(parent.getContext()); - } - // We need to do this because GridView uses the height of the last item - // in a row to determine the height for the entire row. - convertView.setVisibility(View.INVISIBLE); - convertView.setMinimumHeight(footViewContainer.getHeight()); - return convertView; - } - } - throw new ArrayIndexOutOfBoundsException(position); - } - - @Override - public int getItemViewType(int position) { - - final int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - final int adapterViewTypeStart = mAdapter == null ? 0 : mAdapter.getViewTypeCount() - 1; - int type = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER; - if (mCachePlaceHoldView) { - // Header - if (position < numHeadersAndPlaceholders) { - if (position == 0) { - if (mCacheFirstHeaderView) { - type = adapterViewTypeStart + mHeaderViewInfos.size() + mFooterViewInfos.size() + 1 + 1; - } - } - if (position % mNumColumns != 0) { - type = adapterViewTypeStart + (position / mNumColumns + 1); - } - } - } - - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition >= 0 && adjPosition < adapterCount) { - if (adjPosition < mAdapter.getCount()) { - type = mAdapter.getItemViewType(adjPosition); - } else { - if (mCachePlaceHoldView) { - type = adapterViewTypeStart + mHeaderViewInfos.size() + 1; - } - } - } - } - - if (mCachePlaceHoldView) { - // Footer - final int footerPosition = adjPosition - adapterCount; - if (footerPosition >= 0 && footerPosition < getCount() && (footerPosition % mNumColumns) != 0) { - type = adapterViewTypeStart + mHeaderViewInfos.size() + 1 + (footerPosition / mNumColumns + 1); - } - } - if (DEBUG) { - Log.d(LOG_TAG, String.format("getItemViewType: pos: %s, result: %s", position, type, mCachePlaceHoldView, mCacheFirstHeaderView)); - } - return type; - } - - /** - * content view, content view holder, header[0], header and footer placeholder(s) - * - * @return - */ - @Override - public int getViewTypeCount() { - int count = mAdapter == null ? 1 : mAdapter.getViewTypeCount(); - if (mCachePlaceHoldView) { - int offset = mHeaderViewInfos.size() + 1 + mFooterViewInfos.size(); - if (mCacheFirstHeaderView) { - offset += 1; - } - count += offset; - } - if (DEBUG) { - Log.d(LOG_TAG, String.format("getViewTypeCount: %s", count)); - } - return count; - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - mDataSetObservable.registerObserver(observer); - if (mAdapter != null) { - mAdapter.registerDataSetObserver(observer); - } - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - mDataSetObservable.unregisterObserver(observer); - if (mAdapter != null) { - mAdapter.unregisterDataSetObserver(observer); - } - } - - @Override - public Filter getFilter() { - if (mIsFilterable) { - return ((Filterable) mAdapter).getFilter(); - } - return null; - } - - @Override - public ListAdapter getWrappedAdapter() { - return mAdapter; - } - - public void notifyDataSetChanged() { - mDataSetObservable.notifyChanged(); - } - } -} diff --git a/app/src/main/res/layout/song_list_item.xml b/app/src/main/res/layout/song_list_item.xml index 26c89b2b..80996510 100644 --- a/app/src/main/res/layout/song_list_item.xml +++ b/app/src/main/res/layout/song_list_item.xml @@ -3,7 +3,8 @@ android:id="@id/drag_handle" android:orientation="horizontal" android:layout_width="fill_parent" - android:layout_height="?android:attr/listPreferredItemHeight"> + android:layout_height="?android:attr/listPreferredItemHeight" + android:background="@drawable/abc_item_background_holo_light"> Date: Fri, 22 May 2015 17:33:20 -0700 Subject: Add abstract SelectRecyclerFragment --- .../dsub/fragments/SelectRecyclerFragment.java | 191 +++++++++++++++++++++ .../main/res/layout/abstract_recycler_fragment.xml | 26 +++ 2 files changed, 217 insertions(+) create mode 100644 app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java create mode 100644 app/src/main/res/layout/abstract_recycler_fragment.xml (limited to 'app/src/main/res/layout') diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java new file mode 100644 index 00000000..6fd56fd1 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java @@ -0,0 +1,191 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ +package github.daneren2005.dsub.fragments; + +import android.os.Bundle; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.MusicServiceFactory; +import github.daneren2005.dsub.util.BackgroundTask; +import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.ProgressListener; +import github.daneren2005.dsub.util.TabBackgroundTask; +import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.view.GridSpacingDecoration; + +public abstract class SelectRecyclerFragment extends SubsonicFragment { + private static final String TAG = SelectRecyclerFragment.class.getSimpleName(); + protected RecyclerView recyclerView; + protected RecyclerView.Adapter adapter; + protected BackgroundTask> currentTask; + protected List objects; + protected boolean serialize = true; + protected boolean largeCells; + protected int columns; + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + + if(bundle != null && serialize) { + objects = (List) bundle.getSerializable(Constants.FRAGMENT_LIST); + } + largeCells = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true); + columns = context.getResources().getInteger(R.integer.Grid_Columns); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if(serialize) { + outState.putSerializable(Constants.FRAGMENT_LIST, (Serializable) objects); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { + rootView = inflater.inflate(R.layout.abstract_recycler_fragment, container, false); + + refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); + refreshLayout.setOnRefreshListener(this); + + recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); + setupLayoutManager(); + setupScrollList(recyclerView); + + if(objects == null) { + refresh(false); + } else { + recyclerView.setAdapter(adapter = getAdapter(objects)); + } + + return rootView; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { + if(!primaryFragment) { + return; + } + + menuInflater.inflate(getOptionsMenu(), menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return super.onOptionsItemSelected(item); + } + + @Override + protected void refresh(final boolean refresh) { + int titleRes = getTitleResource(); + if(titleRes != 0) { + setTitle(getTitleResource()); + } + recyclerView.setVisibility(View.GONE); + + // Cancel current running task before starting another one + if(currentTask != null) { + currentTask.cancel(); + } + + currentTask = new TabBackgroundTask>(this) { + @Override + protected List doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + + objects = new ArrayList(); + + try { + objects = getObjects(musicService, refresh, this); + } catch (Exception x) { + Log.e(TAG, "Failed to load", x); + } + + return objects; + } + + @Override + protected void done(List result) { + if (result != null && !result.isEmpty()) { + recyclerView.setAdapter(adapter = getAdapter(result)); + + onFinishRefresh(); + recyclerView.setVisibility(View.VISIBLE); + } else { + setEmpty(true); + } + + currentTask = null; + } + }; + currentTask.execute(); + } + + public void setupLayoutManager() { + if(largeCells) { + final int columns = context.getResources().getInteger(R.integer.Grid_Columns); + GridLayoutManager gridLayoutManager = new GridLayoutManager(context, columns); + + GridLayoutManager.SpanSizeLookup spanSizeLookup = getSpanSizeLookup(); + if(spanSizeLookup != null) { + gridLayoutManager.setSpanSizeLookup(spanSizeLookup); + } + RecyclerView.ItemDecoration itemDecoration = getItemDecoration(); + if(itemDecoration != null) { + recyclerView.addItemDecoration(itemDecoration); + } + recyclerView.setLayoutManager(gridLayoutManager); + } else { + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + recyclerView.setLayoutManager(layoutManager); + } + } + public GridLayoutManager.SpanSizeLookup getSpanSizeLookup() { + return null; + } + public RecyclerView.ItemDecoration getItemDecoration() { + return new GridSpacingDecoration(); + } + + public abstract int getOptionsMenu(); + public abstract RecyclerView.Adapter getAdapter(List objs); + public abstract List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception; + public abstract int getTitleResource(); + + public void onFinishRefresh() { + + } +} diff --git a/app/src/main/res/layout/abstract_recycler_fragment.xml b/app/src/main/res/layout/abstract_recycler_fragment.xml new file mode 100644 index 00000000..26c4971c --- /dev/null +++ b/app/src/main/res/layout/abstract_recycler_fragment.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3 From 117c246d7e619ab9a3c0fb36fb152b8ad8bf9afe Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 26 May 2015 18:03:47 -0700 Subject: Abstract out common logic into SectionAdapter --- .../daneren2005/dsub/adapter/EntryGridAdapter.java | 154 ++---------- .../dsub/adapter/EntryInfiniteGridAdapter.java | 8 +- .../daneren2005/dsub/adapter/SectionAdapter.java | 280 +++++++++++++++++++++ .../dsub/fragments/SelectDirectoryFragment.java | 15 +- .../dsub/fragments/SelectRecyclerFragment.java | 13 +- .../daneren2005/dsub/view/BasicHeaderView.java | 37 +++ .../github/daneren2005/dsub/view/UpdateView.java | 21 +- app/src/main/res/layout/basic_header.xml | 11 + app/src/main/res/layout/basic_list_item.xml | 2 +- app/src/main/res/values/strings.xml | 4 +- 10 files changed, 375 insertions(+), 170 deletions(-) create mode 100644 app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java create mode 100644 app/src/main/java/github/daneren2005/dsub/view/BasicHeaderView.java create mode 100644 app/src/main/res/layout/basic_header.xml (limited to 'app/src/main/res/layout') diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java index 80d1ade9..1a4d96a4 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java @@ -16,7 +16,6 @@ package github.daneren2005.dsub.adapter; import android.content.Context; -import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -24,7 +23,6 @@ import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; -import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicDirectory.Entry; import github.daneren2005.dsub.util.ImageLoader; @@ -33,30 +31,21 @@ import github.daneren2005.dsub.view.SongView; import github.daneren2005.dsub.view.UpdateView; import github.daneren2005.dsub.view.UpdateView.UpdateViewHolder; -public class EntryGridAdapter extends RecyclerView.Adapter { +public class EntryGridAdapter extends SectionAdapter { private static String TAG = EntryGridAdapter.class.getSimpleName(); - public static int VIEW_TYPE_HEADER = 0; public static int VIEW_TYPE_ALBUM_CELL = 1; public static int VIEW_TYPE_ALBUM_LINE = 2; public static int VIEW_TYPE_SONG = 3; - protected Context context; - protected List entries; private ImageLoader imageLoader; private boolean largeAlbums; private boolean showArtist = false; private boolean checkable = true; - private OnEntryClickedListener onEntryClickedListener; - private View header; - private List selected = new ArrayList(); - private UpdateView contextView; - private Entry contextEntry; public EntryGridAdapter(Context context, List entries, ImageLoader imageLoader, boolean largeCell) { - this.context = context; - this.entries = entries; + super(context, entries); this.imageLoader = imageLoader; this.largeAlbums = largeCell; @@ -74,11 +63,7 @@ public class EntryGridAdapter extends RecyclerView.Adapter { } @Override - public UpdateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - if(viewType == VIEW_TYPE_HEADER) { - return new UpdateViewHolder(header, false); - } - + public UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { UpdateView updateView = null; if(viewType == VIEW_TYPE_ALBUM_LINE || viewType == VIEW_TYPE_ALBUM_CELL) { updateView = new AlbumView(context, viewType == VIEW_TYPE_ALBUM_CELL); @@ -86,66 +71,12 @@ public class EntryGridAdapter extends RecyclerView.Adapter { updateView = new SongView(context); } - if(viewType != VIEW_TYPE_HEADER && updateView != null) { - final UpdateView view = updateView; - updateView.getChildAt(0).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Entry entry = getEntryForView(view); - - if (view.isCheckable() && view instanceof SongView) { - SongView songView = (SongView) view; - - if (selected.contains(entry)) { - selected.remove(entry); - songView.setChecked(false); - } else { - selected.add(entry); - songView.setChecked(true); - } - } else if (onEntryClickedListener != null) { - onEntryClickedListener.onEntryClicked(entry); - } - } - }); - updateView.getChildAt(0).setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - Entry entry = getEntryForView(view); - - setContextEntry(view, entry); - v.showContextMenu(); - return false; - } - }); - - View moreButton = updateView.findViewById(R.id.more_button); - if(moreButton != null) { - moreButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Entry entry = getEntryForView(view); - setContextEntry(view, entry); - v.showContextMenu(); - } - }); - } - } - return new UpdateViewHolder(updateView); } @Override - public void onBindViewHolder(UpdateViewHolder holder, int position) { - // Header already created - if(header != null && position == 0) { - return; - } - + public void onBindViewHolder(UpdateViewHolder holder, Entry entry, int viewType) { UpdateView view = holder.getUpdateView(); - - int viewType = getItemViewType(position); - Entry entry = getEntryForPosition(position); if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) { AlbumView albumView = (AlbumView) view; albumView.setShowArtist(showArtist); @@ -153,29 +84,25 @@ public class EntryGridAdapter extends RecyclerView.Adapter { } else if(viewType == VIEW_TYPE_SONG) { SongView songView = (SongView) view; songView.setObject(entry, checkable); - songView.setChecked(selected.contains(entry)); } - view.setPosition(position); } @Override - public int getItemCount() { - int size = entries.size(); - - if(header != null) { - size++; + public void setChecked(UpdateView updateView, boolean checked) { + if(updateView instanceof SongView) { + ((SongView) updateView).setChecked(checked); } + } - return size; + public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new UpdateViewHolder(header, false); } + public void onBindHeaderHolder(UpdateViewHolder holder, String header) { - @Override - public int getItemViewType(int position) { - if(header != null && position == 0) { - return VIEW_TYPE_HEADER; - } + } - Entry entry = getEntryForPosition(position); + @Override + public int getItemViewType(Entry entry) { if(entry.isDirectory()) { if (largeAlbums) { return VIEW_TYPE_ALBUM_CELL; @@ -187,20 +114,9 @@ public class EntryGridAdapter extends RecyclerView.Adapter { } } - public Entry getEntryForView(UpdateView view) { - int position = view.getPosition(); - return getEntryForPosition(position); - } - public Entry getEntryForPosition(int position) { - if(header != null) { - position--; - } - - return entries.get(position); - } - public void setHeader(View header) { this.header = header; + this.singleSectionHeader = true; } public void setShowArtist(boolean showArtist) { @@ -210,46 +126,8 @@ public class EntryGridAdapter extends RecyclerView.Adapter { this.checkable = checkable; } - public void setOnEntryClickedListener(OnEntryClickedListener listener) { - this.onEntryClickedListener = listener; - } - - public List getSelected() { - List selected = new ArrayList<>(); - selected.addAll(this.selected); - return selected; - } - public void clearSelected() { - for(Entry entry: selected) { - int index = entries.indexOf(entry); - this.notifyItemChanged(index); - } - selected.clear(); - } - - public void removeEntry(Entry entry) { - int index = entries.indexOf(entry); - if(index != -1) { - removeAt(index); - } - } public void removeAt(int index) { - entries.remove(index); + sections.get(0).remove(index); notifyItemRemoved(index); } - - public void setContextEntry(UpdateView view, Entry entry) { - this.contextView = view; - this.contextEntry = entry; - } - public UpdateView getContextView() { - return contextView; - } - public Entry getContextEntry() { - return contextEntry; - } - - public interface OnEntryClickedListener { - void onEntryClicked(Entry entry); - } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java index 288c38a6..7b7dc6fc 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java @@ -121,7 +121,7 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter { protected List cacheInBackground() throws Exception { MusicService service = MusicServiceFactory.getMusicService(context); MusicDirectory result; - int offset = entries.size(); + int offset = sections.get(0).size(); if(("genres".equals(type) && ServerInfo.checkServerVersion(context, "1.10.0")) || "years".equals(type)) { result = service.getAlbumList(type, extra, size, offset, context, null); } else if("genres".equals(type) || "genres-songs".equals(type)) { @@ -134,13 +134,13 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter { protected void appendCachedData(List newData) { if(newData.size() > 0) { - int start = entries.size(); - entries.addAll(newData); + int start = sections.get(0).size(); + sections.get(0).addAll(newData); this.notifyItemRangeInserted(start, newData.size()); } } protected boolean isLoadingView(int position) { - return !allLoaded && position >= entries.size(); + return !allLoaded && position >= sections.get(0).size(); } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java new file mode 100644 index 00000000..5244c7a6 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java @@ -0,0 +1,280 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.view.BasicHeaderView; +import github.daneren2005.dsub.view.UpdateView; +import github.daneren2005.dsub.view.UpdateView.UpdateViewHolder; + +public abstract class SectionAdapter extends RecyclerView.Adapter> { + private static String TAG = SectionAdapter.class.getSimpleName(); + public static int VIEW_TYPE_HEADER = 0; + + protected Context context; + protected List headers; + protected List> sections; + protected boolean singleSectionHeader; + protected OnItemClickedListener onItemClickedListener; + protected UpdateView contextView; + protected T contextItem; + private List selected = new ArrayList<>(); + + public SectionAdapter(Context context, List section) { + this(context, section, false); + } + public SectionAdapter(Context context, List section, boolean singleSectionHeader) { + this.context = context; + this.headers = Arrays.asList("Section"); + this.sections = new ArrayList<>(); + this.sections.add(section); + this.singleSectionHeader = singleSectionHeader; + } + public SectionAdapter(Context context, List headers, List> sections) { + this(context, headers, sections, true); + } + public SectionAdapter(Context context, List headers, List> sections, boolean singleSectionHeader){ + this.context = context; + this.headers = headers; + this.sections = sections; + this.singleSectionHeader = singleSectionHeader; + } + + @Override + public UpdateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if(viewType == VIEW_TYPE_HEADER) { + return onCreateHeaderHolder(parent); + } else { + final UpdateViewHolder holder = onCreateSectionViewHolder(parent, viewType); + final UpdateView updateView = holder.getUpdateView(); + + if(updateView != null) { + updateView.getChildAt(0).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + T item = holder.getItem(); + if(updateView.isCheckable()) { + if (selected.contains(item)) { + selected.remove(item); + setChecked(updateView, false); + } else { + selected.add(item); + setChecked(updateView, true); + } + } else if(onItemClickedListener != null) { + onItemClickedListener.onItemClicked(item); + } + } + }); + updateView.getChildAt(0).setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + T item = holder.getItem(); + setContextItem(updateView, item); + v.showContextMenu(); + return false; + } + }); + + View moreButton = updateView.findViewById(R.id.more_button); + if(moreButton == null) { + moreButton = updateView.findViewById(R.id.item_more); + } + if (moreButton != null) { + moreButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + T item = holder.getItem(); + setContextItem(updateView, item); + v.showContextMenu(); + } + }); + } + } + + return holder; + } + } + + @Override + public void onBindViewHolder(UpdateViewHolder holder, int position) { + UpdateView updateView = holder.getUpdateView(); + + if(sections.size() == 1 && !singleSectionHeader) { + T item = sections.get(0).get(position); + onBindViewHolder(holder, item, getItemViewType(position)); + if(updateView.isCheckable()) { + setChecked(updateView, selected.contains(item)); + } + holder.setItem(item); + return; + } + + int subPosition = 0; + for(List section: sections) { + if(position == subPosition) { + int index = sections.indexOf(section); + onBindHeaderHolder(holder, headers.get(index)); + return; + } + + if(position <= (subPosition + section.size())) { + T item = section.get(position - subPosition - 1); + onBindViewHolder(holder, item, getItemViewType(item)); + + if(updateView.isCheckable()) { + setChecked(updateView, selected.contains(item)); + } + holder.setItem(item); + return; + } + + subPosition += section.size() + 1; + } + } + + @Override + public int getItemCount() { + if(sections.size() == 1 && !singleSectionHeader) { + return sections.get(0).size(); + } + + int count = headers.size(); + for(List section: sections) { + count += section.size(); + } + + return count; + } + + @Override + public int getItemViewType(int position) { + if(sections.size() == 1 && !singleSectionHeader) { + return getItemViewType(sections.get(0).get(position)); + } + + int subPosition = 0; + for(List section: sections) { + if(position == subPosition) { + return VIEW_TYPE_HEADER; + } + + if(position <= (subPosition + section.size())) { + return getItemViewType(section.get(position - subPosition - 1)); + } + + subPosition += section.size() + 1; + } + + return -1; + } + + public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new UpdateViewHolder(new BasicHeaderView(context)); + } + public void onBindHeaderHolder(UpdateViewHolder holder, String header) { + UpdateView view = holder.getUpdateView(); + view.setObject(header); + } + + public T getItemForPosition(int position) { + if(sections.size() == 1 && !singleSectionHeader) { + return sections.get(0).get(position); + } + + int subPosition = 0; + for(List section: sections) { + if(position == subPosition) { + return null; + } + + if(position <= (subPosition + section.size())) { + return section.get(position - subPosition - 1); + } + + subPosition += section.size() + 1; + } + + return null; + } + + public void setContextItem(UpdateView updateView, T item) { + contextView = updateView; + contextItem = item; + } + public UpdateView getContextView() { + return contextView; + } + public T getContextItem() { + return contextItem; + } + + public void setOnItemClickedListener(OnItemClickedListener onItemClickedListener) { + this.onItemClickedListener = onItemClickedListener; + } + + public List getSelected() { + List selected = new ArrayList<>(); + selected.addAll(this.selected); + return selected; + } + + public void clearSelected() { + // TODO: This needs to work with multiple sections + for(T item: selected) { + int index = sections.get(0).indexOf(item); + this.notifyItemChanged(index); + } + selected.clear(); + } + + public void removeItem(T item) { + int subPosition = 0; + for(List section: sections) { + if(sections.size() > 1 || singleSectionHeader) { + subPosition++; + } + + int index = section.indexOf(item); + if (index != -1) { + section.remove(item); + notifyItemRemoved(subPosition + index); + break; + } + + subPosition += section.size(); + } + } + + public abstract UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType); + public abstract void onBindViewHolder(UpdateViewHolder holder, T item, int viewType); + public abstract int getItemViewType(T item); + public void setChecked(UpdateView updateView, boolean checked) {} + + public interface OnItemClickedListener { + void onItemClicked(T item); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java index d427a26d..f21967b9 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java @@ -34,6 +34,7 @@ import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.adapter.EntryInfiniteGridAdapter; import github.daneren2005.dsub.adapter.EntryGridAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.ArtistInfo; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.ServerInfo; @@ -68,7 +69,7 @@ import java.util.Set; import static github.daneren2005.dsub.domain.MusicDirectory.Entry; -public class SelectDirectoryFragment extends SubsonicFragment implements EntryGridAdapter.OnEntryClickedListener { +public class SelectDirectoryFragment extends SubsonicFragment implements SectionAdapter.OnItemClickedListener { private static final String TAG = SelectDirectoryFragment.class.getSimpleName(); private RecyclerView recyclerView; @@ -341,7 +342,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements EntryGr @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, view, menuInfo); - Entry entry = entryGridAdapter.getContextEntry(); + Entry entry = entryGridAdapter.getContextItem(); UpdateView targetView = entryGridAdapter.getContextView(); menuInfo = new AdapterView.AdapterContextMenuInfo(targetView, 0, 0); @@ -378,7 +379,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements EntryGr if(menuItem.getGroupId() != getSupportTag()) { return false; } - Entry entry = entryGridAdapter.getContextEntry(); + Entry entry = entryGridAdapter.getContextItem(); if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PLAY_NOW_AFTER, false) && menuItem.getItemId() == R.id.song_menu_play_now) { List songs = new ArrayList(); @@ -412,7 +413,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements EntryGr } @Override - public void onEntryClicked(Entry entry) { + public void onItemClicked(Entry entry) { if (entry.isDirectory()) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); @@ -750,7 +751,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements EntryGr } }); } - entryGridAdapter.setOnEntryClickedListener(this); + entryGridAdapter.setOnItemClickedListener(this); // Always show artist if this is not a artist we are viewing if(!artist) { entryGridAdapter.setShowArtist(true); @@ -1054,7 +1055,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements EntryGr @Override protected void done(Void result) { - entryGridAdapter.removeEntry(episode); + entryGridAdapter.removeItem(episode); } @Override @@ -1115,7 +1116,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements EntryGr Util.toast(context, context.getResources().getString(R.string.starring_content_unstarred, Integer.toString(unstar.size()))); for(Entry entry: unstar) { - entryGridAdapter.removeEntry(entry); + entryGridAdapter.removeItem(entry); } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java index c19e9b28..cb2ae6d7 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java @@ -26,32 +26,29 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ListView; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.util.BackgroundTask; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.TabBackgroundTask; -import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.GridSpacingDecoration; public abstract class SelectRecyclerFragment extends SubsonicFragment { private static final String TAG = SelectRecyclerFragment.class.getSimpleName(); protected RecyclerView recyclerView; - protected RecyclerView.Adapter adapter; + protected SectionAdapter adapter; protected BackgroundTask> currentTask; protected List objects; protected boolean serialize = true; - protected boolean largeCells; + protected boolean largeCells = false; protected int columns; @Override @@ -61,7 +58,6 @@ public abstract class SelectRecyclerFragment extends SubsonicFragment { if(bundle != null && serialize) { objects = (List) bundle.getSerializable(Constants.FRAGMENT_LIST); } - largeCells = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true); columns = context.getResources().getInteger(R.integer.Grid_Columns); } @@ -89,6 +85,7 @@ public abstract class SelectRecyclerFragment extends SubsonicFragment { } else { recyclerView.setAdapter(adapter = getAdapter(objects)); } + registerForContextMenu(recyclerView); return rootView; } @@ -190,7 +187,7 @@ public abstract class SelectRecyclerFragment extends SubsonicFragment { } public abstract int getOptionsMenu(); - public abstract RecyclerView.Adapter getAdapter(List objs); + public abstract SectionAdapter getAdapter(List objs); public abstract List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception; public abstract int getTitleResource(); diff --git a/app/src/main/java/github/daneren2005/dsub/view/BasicHeaderView.java b/app/src/main/java/github/daneren2005/dsub/view/BasicHeaderView.java new file mode 100644 index 00000000..d8111692 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/view/BasicHeaderView.java @@ -0,0 +1,37 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.TextView; + +import github.daneren2005.dsub.R; + +public class BasicHeaderView extends UpdateView { + TextView nameView; + + public BasicHeaderView(Context context) { + super(context, false); + + LayoutInflater.from(context).inflate(R.layout.basic_header, this, true); + nameView = (TextView) findViewById(R.id.item_name); + } + + protected void setObjectImpl(Object obj) { + nameView.setText((String) obj); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/view/UpdateView.java b/app/src/main/java/github/daneren2005/dsub/view/UpdateView.java index bdcdc46f..905fbb06 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/UpdateView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/UpdateView.java @@ -66,7 +66,6 @@ public class UpdateView extends LinearLayout { protected SilentBackgroundTask imageTask = null; protected final boolean autoUpdate; - protected int position; protected boolean checkable; public UpdateView(Context context) { @@ -78,8 +77,8 @@ public class UpdateView extends LinearLayout { this.autoUpdate = autoUpdate; setLayoutParams(new AbsListView.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); if(autoUpdate) { INSTANCES.put(this, null); @@ -285,19 +284,13 @@ public class UpdateView extends LinearLayout { } } - public void setPosition(int position) { - this.position = position; - } - public int getPosition() { - return position; - } - public boolean isCheckable() { return checkable; } - public static class UpdateViewHolder extends RecyclerView.ViewHolder { + public static class UpdateViewHolder extends RecyclerView.ViewHolder { private UpdateView updateView; + private T item; public UpdateViewHolder(UpdateView itemView) { super(itemView); @@ -313,5 +306,11 @@ public class UpdateView extends LinearLayout { public UpdateView getUpdateView() { return updateView; } + public void setItem(T item) { + this.item = item; + } + public T getItem() { + return item; + } } } diff --git a/app/src/main/res/layout/basic_header.xml b/app/src/main/res/layout/basic_header.xml new file mode 100644 index 00000000..39f8722d --- /dev/null +++ b/app/src/main/res/layout/basic_header.xml @@ -0,0 +1,11 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/basic_list_item.xml b/app/src/main/res/layout/basic_list_item.xml index 2338f7e0..4974f4f5 100644 --- a/app/src/main/res/layout/basic_list_item.xml +++ b/app/src/main/res/layout/basic_list_item.xml @@ -3,7 +3,7 @@ android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:background="@android:color/transparent"> + android:background="@drawable/abc_item_background_holo_light"> Starred \"%s\" Unstarred \"%s\" Failed to update \"%s\", please try later. - + + My Playlists + Shared Playlists Failed to grab list of playlists Added %1$s songs to \"%2$s\" Failed to update \"%s\", please try later. -- cgit v1.2.3 From 50a5cee52fd0c0dd08a00ad59c2f9c2751e65834 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Thu, 28 May 2015 08:39:41 -0700 Subject: Convert a bunch of other fragments to RecyclerView --- .../daneren2005/dsub/adapter/BasicListAdapter.java | 48 +++++++++++++ .../daneren2005/dsub/adapter/BookmarkAdapter.java | 53 +++++++------- .../daneren2005/dsub/adapter/EntryGridAdapter.java | 2 +- .../daneren2005/dsub/adapter/GenreAdapter.java | 80 +++++++++------------- .../dsub/adapter/PodcastChannelAdapter.java | 79 +++++++++------------ .../daneren2005/dsub/adapter/SectionAdapter.java | 28 +++++--- .../daneren2005/dsub/adapter/ShareAdapter.java | 75 +++++++++----------- .../daneren2005/dsub/adapter/UserAdapter.java | 34 +++++---- .../daneren2005/dsub/fragments/AdminFragment.java | 14 ++-- .../dsub/fragments/SelectBookmarkFragment.java | 16 +++-- .../dsub/fragments/SelectGenreFragment.java | 40 +++++------ .../dsub/fragments/SelectPodcastsFragment.java | 57 ++++++--------- .../dsub/fragments/SelectRecyclerFragment.java | 9 ++- .../dsub/fragments/SelectShareFragment.java | 38 +++++----- .../dsub/fragments/SelectVideoFragment.java | 24 ++++--- .../dsub/fragments/SelectYearFragment.java | 36 ++++------ .../dsub/fragments/SubsonicFragment.java | 6 +- .../github/daneren2005/dsub/util/UserUtil.java | 6 +- .../daneren2005/dsub/view/BasicListView.java | 45 ++++++++++++ .../github/daneren2005/dsub/view/SongView.java | 2 +- app/src/main/res/layout/genre_list_item.xml | 2 +- app/src/main/res/layout/user_list_item.xml | 2 +- 22 files changed, 377 insertions(+), 319 deletions(-) create mode 100644 app/src/main/java/github/daneren2005/dsub/adapter/BasicListAdapter.java create mode 100644 app/src/main/java/github/daneren2005/dsub/view/BasicListView.java (limited to 'app/src/main/res/layout') diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/BasicListAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/BasicListAdapter.java new file mode 100644 index 00000000..dfea91bf --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/BasicListAdapter.java @@ -0,0 +1,48 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.view.ViewGroup; + +import java.util.List; + +import github.daneren2005.dsub.view.BasicListView; +import github.daneren2005.dsub.view.UpdateView; + +public class BasicListAdapter extends SectionAdapter { + public static int VIEW_TYPE_LINE = 1; + + public BasicListAdapter(Context context, List strings, OnItemClickedListener listener) { + super(context, strings); + this.onItemClickedListener = listener; + } + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new BasicListView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, String item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(String item) { + return VIEW_TYPE_LINE; + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/BookmarkAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/BookmarkAdapter.java index 26d3e16a..8335966d 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/BookmarkAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/BookmarkAdapter.java @@ -1,20 +1,16 @@ /* - This file is part of Subsonic. - + This file is part of Subsonic. Subsonic is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Subsonic 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. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along with Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus + Copyright 2015 (C) Scott Jackson */ package github.daneren2005.dsub.adapter; @@ -22,9 +18,7 @@ package github.daneren2005.dsub.adapter; import android.content.Context; import java.util.List; -import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import android.widget.TextView; import github.daneren2005.dsub.R; @@ -32,33 +26,36 @@ import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.SongView; +import github.daneren2005.dsub.view.UpdateView; -public class BookmarkAdapter extends ArrayAdapter { +public class BookmarkAdapter extends SectionAdapter { private final static String TAG = BookmarkAdapter.class.getSimpleName(); - private Context activity; - public BookmarkAdapter(Context activity, List bookmarks) { - super(activity, android.R.layout.simple_list_item_1, bookmarks); - this.activity = activity; + public BookmarkAdapter(Context activity, List bookmarks, OnItemClickedListener listener) { + super(activity, bookmarks); + this.onItemClickedListener = listener; } - - public View getView(int position, View convertView, ViewGroup parent) { - MusicDirectory.Entry entry = getItem(position); - Bookmark bookmark = entry.getBookmark(); - SongView view; - if (convertView != null) { - view = (SongView) convertView; - } else { - view = new SongView(activity); - } - view.setObject(entry, false); - + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new SongView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, MusicDirectory.Entry item, int viewType) { + SongView songView = (SongView) holder.getUpdateView(); + Bookmark bookmark = item.getBookmark(); + + songView.setObject(item, false); + // Add current position to duration - TextView durationTextView = (TextView) view.findViewById(R.id.song_duration); + TextView durationTextView = (TextView) songView.findViewById(R.id.song_duration); String duration = durationTextView.getText().toString(); durationTextView.setText(Util.formatDuration(bookmark.getPosition() / 1000) + " / " + duration); - - return view; + } + + @Override + public int getItemViewType(MusicDirectory.Entry item) { + return EntryGridAdapter.VIEW_TYPE_SONG; } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java index 1a4d96a4..48b278ec 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java @@ -83,7 +83,7 @@ public class EntryGridAdapter extends SectionAdapter { albumView.setObject(entry, imageLoader); } else if(viewType == VIEW_TYPE_SONG) { SongView songView = (SongView) view; - songView.setObject(entry, checkable); + songView.setObject(entry, checkable && !entry.isVideo()); } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/GenreAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/GenreAdapter.java index abb208c9..7e6954f9 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/GenreAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/GenreAdapter.java @@ -1,60 +1,48 @@ /* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic 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. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see . + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ - Copyright 2010 (C) Sindre Mehus - */ package github.daneren2005.dsub.adapter; -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; import android.content.Context; -import android.view.View; import android.view.ViewGroup; -import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.view.GenreView; +import github.daneren2005.dsub.view.UpdateView; import java.util.List; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; -/** - * @author Sindre Mehus -*/ -public class GenreAdapter extends ArrayAdapter{ - private Context activity; - private List genres; - - public GenreAdapter(Context context, List genres) { - super(context, android.R.layout.simple_list_item_1, genres); - this.activity = context; - this.genres = genres; +public class GenreAdapter extends SectionAdapter{ + public static int VIEW_TYPE_GENRE = 1; + + public GenreAdapter(Context context, List genres, OnItemClickedListener listener) { + super(context, genres); + this.onItemClickedListener = listener; } - + @Override - public View getView(int position, View convertView, ViewGroup parent) { - Genre genre = genres.get(position); - GenreView view; - if (convertView != null && convertView instanceof GenreView) { - view = (GenreView) convertView; - } else { - view = new GenreView(activity); - } - view.setObject(genre); - return view; - } + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new GenreView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Genre item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(Genre item) { + return VIEW_TYPE_GENRE; + } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java index 8ee39a10..dc94178d 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java @@ -1,60 +1,47 @@ /* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic 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. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ package github.daneren2005.dsub.adapter; -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; import android.content.Context; -import android.view.View; import android.view.ViewGroup; -import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.PodcastChannel; import github.daneren2005.dsub.view.PodcastChannelView; +import github.daneren2005.dsub.view.UpdateView; import java.util.List; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; -/** - * @author Sindre Mehus -*/ -public class PodcastChannelAdapter extends ArrayAdapter{ - private Context activity; - private List podcasts; +public class PodcastChannelAdapter extends SectionAdapter{ + public static int VIEW_TYPE_PODCAST = 1; - public PodcastChannelAdapter(Context context, List podcasts) { - super(context, android.R.layout.simple_list_item_1, podcasts); - this.activity = context; - this.podcasts = podcasts; + public PodcastChannelAdapter(Context context, List podcasts, OnItemClickedListener listener) { + super(context, podcasts); + this.onItemClickedListener = listener; } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - PodcastChannel podcast = podcasts.get(position); - PodcastChannelView view; - if (convertView != null && convertView instanceof PodcastChannelView) { - view = (PodcastChannelView) convertView; - } else { - view = new PodcastChannelView(activity); - } - view.setObject(podcast); - return view; + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new PodcastChannelView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, PodcastChannel item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(PodcastChannel item) { + return VIEW_TYPE_PODCAST; } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java index 5244c7a6..84b21e30 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java @@ -76,7 +76,7 @@ public abstract class SectionAdapter extends RecyclerView.Adapter extends RecyclerView.Adapter extends RecyclerView.Adapter extends RecyclerView.Adapter. + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ - Copyright 2010 (C) Sindre Mehus - */ package github.daneren2005.dsub.adapter; import android.content.Context; -import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import java.util.List; import github.daneren2005.dsub.domain.Share; import github.daneren2005.dsub.view.ShareView; +import github.daneren2005.dsub.view.UpdateView; -/** - * @author Sindre Mehus -*/ -public class ShareAdapter extends ArrayAdapter{ - private Context activity; - private List shares; - - public ShareAdapter(Context context, List shares) { - super(context, android.R.layout.simple_list_item_1, shares); - this.activity = context; - this.shares = shares; +public class ShareAdapter extends SectionAdapter{ + public static int VIEW_TYPE_SHARE = 1; + + public ShareAdapter(Context context, List shares, OnItemClickedListener listener) { + super(context, shares); + this.onItemClickedListener = listener; } - + @Override - public View getView(int position, View convertView, ViewGroup parent) { - Share share = shares.get(position); - ShareView view; - if (convertView != null && convertView instanceof ShareView) { - view = (ShareView) convertView; - } else { - view = new ShareView(activity); - } - view.setObject(share); - return view; - } + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new ShareView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Share item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(Share item) { + return VIEW_TYPE_SHARE; + } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/UserAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/UserAdapter.java index f0f78d97..95809e48 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/UserAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/UserAdapter.java @@ -25,28 +25,32 @@ import java.util.List; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.view.UpdateView; import github.daneren2005.dsub.view.UserView; -public class UserAdapter extends ArrayAdapter { - private final Context activity; +public class UserAdapter extends SectionAdapter { + public static int VIEW_TYPE_USER = 1; + private final ImageLoader imageLoader; - public UserAdapter(Context activity, List users, ImageLoader imageLoader) { - super(activity, R.layout.basic_list_item, users); - this.activity = activity; + public UserAdapter(Context context, List users, ImageLoader imageLoader, OnItemClickedListener listener) { + super(context, users); this.imageLoader = imageLoader; + this.onItemClickedListener = listener; + } + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new UserView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, User item, int viewType) { + holder.getUpdateView().setObject(item, imageLoader); } @Override - public View getView(int position, View convertView, ViewGroup parent) { - User entry = getItem(position); - UserView view; - if (convertView != null && convertView instanceof UserView) { - view = (UserView) convertView; - } else { - view = new UserView(activity); - } - view.setObject(entry, imageLoader); - return view; + public int getItemViewType(User item) { + return VIEW_TYPE_USER; } } \ No newline at end of file diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java index 66ce5f15..f3f9eb64 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.parser.SubsonicRESTException; @@ -37,7 +38,7 @@ import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.adapter.UserAdapter; -public class AdminFragment extends SelectListFragment { +public class AdminFragment extends SelectRecyclerFragment { private static String TAG = AdminFragment.class.getSimpleName(); @Override @@ -69,8 +70,7 @@ public class AdminFragment extends SelectListFragment { @Override public boolean onContextItemSelected(MenuItem menuItem) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - User user = objects.get(info.position); + User user = adapter.getContextItem(); switch(menuItem.getItemId()) { case R.id.admin_change_email: @@ -97,8 +97,8 @@ public class AdminFragment extends SelectListFragment { } @Override - public ArrayAdapter getAdapter(List objs) { - return new UserAdapter(context, objs, getImageLoader()); + public SectionAdapter getAdapter(List objs) { + return new UserAdapter(context, objs, getImageLoader(), this); } @Override @@ -134,9 +134,7 @@ public class AdminFragment extends SelectListFragment { } @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - User user = (User) parent.getItemAtPosition(position); - + public void onItemClicked(User user) { SubsonicFragment fragment = new UserFragment(); Bundle args = new Bundle(); args.putSerializable(Constants.INTENT_EXTRA_NAME_ID, user); diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java index 830e2957..a774a287 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java @@ -25,6 +25,7 @@ import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.service.DownloadService; @@ -33,16 +34,19 @@ import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.adapter.BookmarkAdapter; +import github.daneren2005.dsub.view.UpdateView; import java.util.Arrays; import java.util.List; -public class SelectBookmarkFragment extends SelectListFragment { +public class SelectBookmarkFragment extends SelectRecyclerFragment { private static final String TAG = SelectBookmarkFragment.class.getSimpleName(); @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, view, menuInfo); + UpdateView targetView = adapter.getContextView(); + menuInfo = new AdapterView.AdapterContextMenuInfo(targetView, 0, 0); MenuInflater inflater = context.getMenuInflater(); inflater.inflate(R.menu.select_bookmark_context, menu); @@ -52,8 +56,7 @@ public class SelectBookmarkFragment extends SelectListFragment bookmarks) { - return new BookmarkAdapter(context, bookmarks); + public SectionAdapter getAdapter(List bookmarks) { + return new BookmarkAdapter(context, bookmarks, this); } @Override @@ -92,13 +95,12 @@ public class SelectBookmarkFragment extends SelectListFragment parent, View view, int position, long id) { + public void onItemClicked(final MusicDirectory.Entry bookmark) { final DownloadService downloadService = getDownloadService(); if(downloadService == null) { return; } - final MusicDirectory.Entry bookmark = (MusicDirectory.Entry) parent.getItemAtPosition(position); new SilentBackgroundTask(context) { @Override protected Void doInBackground() throws Throwable { diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectGenreFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectGenreFragment.java index 2d310172..fe012f62 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectGenreFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectGenreFragment.java @@ -1,21 +1,18 @@ /* - This file is part of Subsonic. + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic 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. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ package github.daneren2005.dsub.fragments; import android.os.Bundle; @@ -23,6 +20,7 @@ import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.util.Constants; @@ -31,7 +29,7 @@ import github.daneren2005.dsub.adapter.GenreAdapter; import java.util.List; -public class SelectGenreFragment extends SelectListFragment { +public class SelectGenreFragment extends SelectRecyclerFragment { private static final String TAG = SelectGenreFragment.class.getSimpleName(); @Override @@ -40,8 +38,8 @@ public class SelectGenreFragment extends SelectListFragment { } @Override - public ArrayAdapter getAdapter(List objs) { - return new GenreAdapter(context, objs); + public SectionAdapter getAdapter(List objs) { + return new GenreAdapter(context, objs, this); } @Override @@ -55,9 +53,7 @@ public class SelectGenreFragment extends SelectListFragment { } @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Genre genre = (Genre) parent.getItemAtPosition(position); - + public void onItemClicked(Genre genre) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "genres"); diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java index 3a564f1c..eebb1a8a 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java @@ -1,21 +1,17 @@ /* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic 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. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ package github.daneren2005.dsub.fragments; import android.app.AlertDialog; @@ -24,10 +20,9 @@ import android.os.Bundle; import android.view.ContextMenu; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.TextView; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PodcastChannel; import github.daneren2005.dsub.service.MusicService; @@ -46,11 +41,7 @@ import github.daneren2005.dsub.adapter.PodcastChannelAdapter; import java.util.ArrayList; import java.util.List; -/** - * - * @author Scott - */ -public class SelectPodcastsFragment extends SelectListFragment { +public class SelectPodcastsFragment extends SelectRecyclerFragment { private static final String TAG = SelectPodcastsFragment.class.getSimpleName(); @Override @@ -79,8 +70,7 @@ public class SelectPodcastsFragment extends SelectListFragment { if(!Util.isOffline(context) && UserUtil.canPodcast()) { inflater.inflate(R.menu.select_podcasts_context, menu); - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - PodcastChannel podcast = (PodcastChannel) listView.getItemAtPosition(info.position); + PodcastChannel podcast = adapter.getContextItem(); if(SyncUtil.isSyncedPodcast(context, podcast.getId())) { menu.removeItem(R.id.podcast_menu_sync); } else { @@ -98,10 +88,8 @@ public class SelectPodcastsFragment extends SelectListFragment { if(menuItem.getGroupId() != getSupportTag()) { return false; } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - PodcastChannel channel = (PodcastChannel) listView.getItemAtPosition(info.position); + PodcastChannel channel = adapter.getContextItem(); switch (menuItem.getItemId()) { case R.id.podcast_menu_sync: syncPodcast(channel); @@ -126,8 +114,8 @@ public class SelectPodcastsFragment extends SelectListFragment { } @Override - public ArrayAdapter getAdapter(List channels) { - return new PodcastChannelAdapter(context, channels); + public SectionAdapter getAdapter(List channels) { + return new PodcastChannelAdapter(context, channels, this); } @Override @@ -141,9 +129,7 @@ public class SelectPodcastsFragment extends SelectListFragment { } @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - PodcastChannel channel = (PodcastChannel) parent.getItemAtPosition(position); - + public void onItemClicked(PodcastChannel channel) { if("error".equals(channel.getStatus())) { Util.toast(context, context.getResources().getString(R.string.select_podcasts_invalid_podcast_channel, channel.getErrorMessage() == null ? "error" : channel.getErrorMessage())); } else if("downloading".equals(channel.getStatus())) { @@ -258,8 +244,7 @@ public class SelectPodcastsFragment extends SelectListFragment { @Override protected void done(Void result) { - adapter.remove(channel); - adapter.notifyDataSetChanged(); + adapter.removeItem(channel); Util.toast(context, context.getResources().getString(R.string.select_podcasts_deleted, channel.getName())); } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java index afcbf273..bd4d9526 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java @@ -12,6 +12,7 @@ along with Subsonic. If not, see . Copyright 2015 (C) Scott Jackson */ + package github.daneren2005.dsub.fragments; import android.os.Bundle; @@ -50,6 +51,7 @@ public abstract class SelectRecyclerFragment extends SubsonicFragment impleme protected boolean serialize = true; protected boolean largeCells = false; protected int columns; + protected boolean pullToRefresh = true; @Override public void onCreate(Bundle bundle) { @@ -78,7 +80,12 @@ public abstract class SelectRecyclerFragment extends SubsonicFragment impleme recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); setupLayoutManager(); - setupScrollList(recyclerView); + + if(pullToRefresh) { + setupScrollList(recyclerView); + } else { + refreshLayout.setEnabled(false); + } if(objects == null) { refresh(false); diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java index 07cd3bef..87dd55b4 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java @@ -1,3 +1,18 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ + package github.daneren2005.dsub.fragments; import android.app.AlertDialog; @@ -6,8 +21,6 @@ import android.os.Bundle; import android.view.ContextMenu; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.DatePicker; @@ -17,6 +30,7 @@ import java.util.Date; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Share; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; @@ -28,10 +42,7 @@ import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.adapter.ShareAdapter; -/** - * Created by Scott on 12/28/13. - */ -public class SelectShareFragment extends SelectListFragment { +public class SelectShareFragment extends SelectRecyclerFragment { private static final String TAG = SelectShareFragment.class.getSimpleName(); @Override @@ -48,9 +59,7 @@ public class SelectShareFragment extends SelectListFragment { return false; } - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Share share = (Share) listView.getItemAtPosition(info.position); - + Share share = adapter.getContextItem(); switch (menuItem.getItemId()) { case R.id.share_menu_share: shareExternal(share); @@ -75,8 +84,8 @@ public class SelectShareFragment extends SelectListFragment { } @Override - public ArrayAdapter getAdapter(List objs) { - return new ShareAdapter(context, objs); + public SectionAdapter getAdapter(List objs) { + return new ShareAdapter(context, objs, this); } @Override @@ -90,9 +99,7 @@ public class SelectShareFragment extends SelectListFragment { } @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Share share = (Share) parent.getItemAtPosition(position); - + public void onItemClicked(Share share) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); args.putSerializable(Constants.INTENT_EXTRA_NAME_SHARE, share); @@ -193,8 +200,7 @@ public class SelectShareFragment extends SelectListFragment { @Override protected void done(Void result) { - adapter.remove(share); - adapter.notifyDataSetChanged(); + adapter.removeItem(share); Util.toast(context, context.getResources().getString(R.string.share_deleted, share.getName())); } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectVideoFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectVideoFragment.java index b4d34ff9..e91a163c 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectVideoFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectVideoFragment.java @@ -24,20 +24,25 @@ import android.widget.ArrayAdapter; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.EntryGridAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.adapter.EntryAdapter; +import github.daneren2005.dsub.view.UpdateView; -public class SelectVideoFragment extends SelectListFragment { +public class SelectVideoFragment extends SelectRecyclerFragment { @Override public int getOptionsMenu() { return R.menu.empty; } @Override - public ArrayAdapter getAdapter(List objs) { - return new EntryAdapter(context, null, objs, false); + public SectionAdapter getAdapter(List objs) { + SectionAdapter adapter = new EntryGridAdapter(context, objs, null, false); + adapter.setOnItemClickedListener(this); + return adapter; } @Override @@ -52,18 +57,17 @@ public class SelectVideoFragment extends SelectListFragment parent, View view, int position, long id) { - MusicDirectory.Entry entry = (MusicDirectory.Entry) parent.getItemAtPosition(position); + public void onItemClicked(MusicDirectory.Entry entry) { playVideo(entry); } @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, view, menuInfo); + UpdateView targetView = adapter.getContextView(); + menuInfo = new AdapterView.AdapterContextMenuInfo(targetView, 0, 0); - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object entry = listView.getItemAtPosition(info.position); - + MusicDirectory.Entry entry = adapter.getContextItem(); onCreateContextMenu(menu, view, menuInfo, entry); recreateContextMenu(menu); } @@ -74,9 +78,7 @@ public class SelectVideoFragment extends SelectListFragment. - - Copyright 2010 (C) Sindre Mehus + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson */ + package github.daneren2005.dsub.fragments; import android.os.Bundle; @@ -27,14 +24,13 @@ import java.util.ArrayList; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.BasicListAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.ProgressListener; -/** - * Created by Scott on 12/23/13. - */ -public class SelectYearFragment extends SelectListFragment { +public class SelectYearFragment extends SelectRecyclerFragment { @Override public int getOptionsMenu() { @@ -42,15 +38,15 @@ public class SelectYearFragment extends SelectListFragment { } @Override - public ArrayAdapter getAdapter(List objs) { - return new ArrayAdapter(context, android.R.layout.simple_list_item_1, objs); + public SectionAdapter getAdapter(List objs) { + return new BasicListAdapter(context, objs, this); } @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - List decades = new ArrayList(); + public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { + List decades = new ArrayList<>(); for(int i = 2010; i >= 1920; i -= 10) { - decades.add(i); + decades.add(String.valueOf(i)); } return decades; @@ -62,15 +58,13 @@ public class SelectYearFragment extends SelectListFragment { } @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Integer decade = (Integer) parent.getItemAtPosition(position); - + public void onItemClicked(String decade) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "years"); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); - args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, Integer.toString(decade)); + args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, decade); fragment.setArguments(args); replaceFragment(fragment); diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java index 6070185d..82d5d97f 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java @@ -54,6 +54,7 @@ import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.activity.SubsonicActivity; import github.daneren2005.dsub.activity.SubsonicFragmentActivity; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Artist; import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.Genre; @@ -1627,7 +1628,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR }.execute(); } - protected void deleteBookmark(final MusicDirectory.Entry entry, final ArrayAdapter adapter) { + protected void deleteBookmark(final MusicDirectory.Entry entry, final SectionAdapter adapter) { Util.confirmDialog(context, R.string.bookmark_delete_title, entry.getTitle(), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -1653,8 +1654,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR @Override protected void done(Void result) { if (adapter != null) { - adapter.remove(entry); - adapter.notifyDataSetChanged(); + adapter.removeItem(entry); } Util.toast(context, context.getResources().getString(R.string.bookmark_deleted, entry.getTitle())); } diff --git a/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java b/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java index 29618424..5c5f1543 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java +++ b/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java @@ -28,6 +28,7 @@ import android.widget.ListView; import android.widget.TextView; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.fragments.SubsonicFragment; import github.daneren2005.dsub.service.DownloadService; @@ -326,7 +327,7 @@ public final class UserUtil { }); } - public static void deleteUser(final Context context, final User user, final ArrayAdapter adapter) { + public static void deleteUser(final Context context, final User user, final SectionAdapter adapter) { Util.confirmDialog(context, R.string.common_delete, user.getUsername(), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -341,8 +342,7 @@ public final class UserUtil { @Override protected void done(Void v) { if(adapter != null) { - adapter.remove(user); - adapter.notifyDataSetChanged(); + adapter.removeItem(user); } Util.toast(context, context.getResources().getString(R.string.admin_delete_user_success, user.getUsername())); diff --git a/app/src/main/java/github/daneren2005/dsub/view/BasicListView.java b/app/src/main/java/github/daneren2005/dsub/view/BasicListView.java new file mode 100644 index 00000000..3169f903 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/view/BasicListView.java @@ -0,0 +1,45 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic 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. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import github.daneren2005.dsub.R; + +public class BasicListView extends UpdateView { + private TextView titleView; + + public BasicListView(Context context) { + super(context, false); + this.context = context; + LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); + + titleView = (TextView) findViewById(R.id.item_name); + starButton = (ImageButton) findViewById(R.id.item_star); + starButton.setFocusable(false); + moreButton = (ImageView) findViewById(R.id.item_more); + moreButton.setVisibility(View.GONE); + } + + protected void setObjectImpl(Object obj) { + titleView.setText((String) obj); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/view/SongView.java b/app/src/main/java/github/daneren2005/dsub/view/SongView.java index a5522719..49a09578 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/SongView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/SongView.java @@ -140,7 +140,7 @@ public class SongView extends UpdateView implements Checkable { titleTextView.setText(title); artistTextView.setText(artist); - checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE); + checkedTextView.setVisibility(checkable ? View.VISIBLE : View.GONE); this.setBackgroundColor(0x00000000); ratingBar.setVisibility(View.GONE); diff --git a/app/src/main/res/layout/genre_list_item.xml b/app/src/main/res/layout/genre_list_item.xml index 6affa24c..9a6e4245 100644 --- a/app/src/main/res/layout/genre_list_item.xml +++ b/app/src/main/res/layout/genre_list_item.xml @@ -3,7 +3,7 @@ android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:background="@android:color/transparent"> + android:background="@drawable/abc_item_background_holo_light"> + android:background="@drawable/abc_item_background_holo_light"> Date: Thu, 28 May 2015 17:58:08 -0700 Subject: Use ripple selector instead of basic holo one --- app/src/main/res/layout/album_cell_item.xml | 2 +- app/src/main/res/layout/basic_list_item.xml | 2 +- app/src/main/res/layout/genre_list_item.xml | 2 +- app/src/main/res/layout/song_list_item.xml | 2 +- app/src/main/res/layout/user_list_item.xml | 2 +- app/src/main/res/values/styles.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'app/src/main/res/layout') diff --git a/app/src/main/res/layout/album_cell_item.xml b/app/src/main/res/layout/album_cell_item.xml index 46e2b1a6..fe634c13 100644 --- a/app/src/main/res/layout/album_cell_item.xml +++ b/app/src/main/res/layout/album_cell_item.xml @@ -3,7 +3,7 @@ android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@drawable/abc_item_background_holo_light"> + android:background="?attr/selectableItemBackground"> + android:background="?attr/selectableItemBackground"> + android:background="?attr/selectableItemBackground"> + android:background="?attr/selectableItemBackground"> + android:background="?attr/selectableItemBackground">