Refactored ListView into RecycleView

Implemented custom RecyclerView to support using an empty view and a
    auto fitted grid layout.

    Reenabled shared element transitions for Oreo
This commit is contained in:
Martijn Brekhof 2018-07-24 22:04:33 +02:00
parent f985f4132d
commit 3f5ccefe2e
41 changed files with 1223 additions and 891 deletions

View File

@ -102,6 +102,7 @@ dependencies {
implementation "com.android.support:preference-v14:${supportLibVersion}" implementation "com.android.support:preference-v14:${supportLibVersion}"
implementation "com.android.support:support-v13:${supportLibVersion}" implementation "com.android.support:support-v13:${supportLibVersion}"
implementation "com.android.support:design:${supportLibVersion}" implementation "com.android.support:design:${supportLibVersion}"
implementation "com.android.support:recyclerview-v7:${supportLibVersion}"
implementation 'com.fasterxml.jackson.core:jackson-databind:2.5.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.5.2'
implementation 'com.jakewharton:butterknife:8.8.1' implementation 'com.jakewharton:butterknife:8.8.1'

View File

@ -27,6 +27,7 @@ import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader; import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.support.v4.view.MenuItemCompat; import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -35,8 +36,6 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.CursorAdapter;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Toast; import android.widget.Toast;
@ -48,6 +47,7 @@ import org.xbmc.kore.jsonrpc.event.MediaSyncEvent;
import org.xbmc.kore.service.library.LibrarySyncService; import org.xbmc.kore.service.library.LibrarySyncService;
import org.xbmc.kore.service.library.SyncItem; import org.xbmc.kore.service.library.SyncItem;
import org.xbmc.kore.service.library.SyncUtils; import org.xbmc.kore.service.library.SyncUtils;
import org.xbmc.kore.ui.viewgroups.RecyclerViewEmptyViewSupport;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
@ -78,6 +78,7 @@ public abstract class AbstractCursorListFragment extends AbstractListFragment
abstract protected void onListItemClicked(View view); abstract protected void onListItemClicked(View view);
abstract protected CursorLoader createCursorLoader(); abstract protected CursorLoader createCursorLoader();
abstract protected RecyclerViewCursorAdapter createCursorAdapter();
@TargetApi(16) @TargetApi(16)
@Nullable @Nullable
@ -136,16 +137,21 @@ public abstract class AbstractCursorListFragment extends AbstractListFragment
} }
@Override @Override
protected AdapterView.OnItemClickListener createOnItemClickListener() { protected RecyclerViewEmptyViewSupport.OnItemClickListener createOnItemClickListener() {
return new AdapterView.OnItemClickListener() { return new RecyclerViewEmptyViewSupport.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(View view, int position) {
saveSearchState(); saveSearchState();
onListItemClicked(view); onListItemClicked(view);
} }
}; };
} }
@Override
final protected RecyclerView.Adapter createAdapter() {
return createCursorAdapter();
}
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.abstractcursorlistfragment, menu); inflater.inflate(R.menu.abstractcursorlistfragment, menu);
@ -305,7 +311,7 @@ public abstract class AbstractCursorListFragment extends AbstractListFragment
@Override @Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
loaderLoading = false; loaderLoading = false;
((CursorAdapter) getAdapter()).swapCursor(cursor); ((RecyclerViewCursorAdapter) getAdapter()).swapCursor(cursor);
if (TextUtils.isEmpty(searchFilter)) { if (TextUtils.isEmpty(searchFilter)) {
// To prevent the empty text from appearing on the first load, set it now // To prevent the empty text from appearing on the first load, set it now
emptyView.setText(getString(R.string.swipe_down_to_refresh)); emptyView.setText(getString(R.string.swipe_down_to_refresh));
@ -316,7 +322,7 @@ public abstract class AbstractCursorListFragment extends AbstractListFragment
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void onLoaderReset(Loader<Cursor> cursorLoader) { public void onLoaderReset(Loader<Cursor> cursorLoader) {
((CursorAdapter) getAdapter()).swapCursor(null); ((RecyclerViewCursorAdapter) getAdapter()).swapCursor(null);
} }
/** /**

View File

@ -23,43 +23,37 @@ import android.preference.PreferenceManager;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.TextView; import android.widget.TextView;
import org.xbmc.kore.R; import org.xbmc.kore.R;
import org.xbmc.kore.Settings; import org.xbmc.kore.Settings;
import org.xbmc.kore.ui.viewgroups.RecyclerViewEmptyViewSupport;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.Utils;
import butterknife.ButterKnife;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder; import butterknife.Unbinder;
public abstract class AbstractListFragment extends Fragment implements public abstract class AbstractListFragment extends Fragment implements
SwipeRefreshLayout.OnRefreshListener { SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = LogUtils.makeLogTag(AbstractListFragment.class); private static final String TAG = LogUtils.makeLogTag(AbstractListFragment.class);
private BaseAdapter adapter; private RecyclerView.Adapter adapter;
private final String BUNDLE_SAVEDINSTANCE_LISTPOSITION = "lposition";
private boolean gridViewUsesMultipleColumns;
private Unbinder unbinder; private Unbinder unbinder;
protected @BindView(R.id.swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout; protected @BindView(R.id.swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.list) GridView gridView; @BindView(R.id.list) RecyclerViewEmptyViewSupport recyclerView;
@BindView(android.R.id.empty) TextView emptyView; @BindView(android.R.id.empty) TextView emptyView;
abstract protected AdapterView.OnItemClickListener createOnItemClickListener(); abstract protected RecyclerViewEmptyViewSupport.OnItemClickListener createOnItemClickListener();
abstract protected BaseAdapter createAdapter(); abstract protected RecyclerViewEmptyViewSupport.Adapter createAdapter();
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
@ -76,40 +70,18 @@ public abstract class AbstractListFragment extends Fragment implements
swipeRefreshLayout.setOnRefreshListener(this); swipeRefreshLayout.setOnRefreshListener(this);
gridView.setEmptyView(emptyView); recyclerView.setEmptyView(emptyView);
gridView.setOnItemClickListener(createOnItemClickListener()); recyclerView.setOnItemClickListener(createOnItemClickListener());
gridView.setAdapter(adapter);
if (savedInstanceState != null) { if (PreferenceManager
final int listPosition = savedInstanceState.getInt(BUNDLE_SAVEDINSTANCE_LISTPOSITION); .getDefaultSharedPreferences(getActivity())
gridView.post(new Runnable() { .getBoolean(Settings.KEY_PREF_SINGLE_COLUMN,
@Override Settings.DEFAULT_PREF_SINGLE_COLUMN)) {
public void run() { recyclerView.setColumnCount(1);
gridView.setSelection(listPosition);
}
});
} }
//Listener added to be able to determine if multiple-columns is at all possible for the current grid recyclerView.setAdapter(adapter);
//We use this information to enable/disable the menu item to switch between multiple and single columns
gridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (gridView.getNumColumns() > 1) {
gridViewUsesMultipleColumns = true;
}
if (Utils.isJellybeanOrLater()) {
gridView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
gridView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
//Make sure menu is update d if it was already created
getActivity().invalidateOptionsMenu();
}
});
setHasOptionsMenu(true); setHasOptionsMenu(true);
return root; return root;
@ -121,34 +93,23 @@ public abstract class AbstractListFragment extends Fragment implements
unbinder.unbind(); unbinder.unbind();
} }
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (gridView != null) {
outState.putInt(BUNDLE_SAVEDINSTANCE_LISTPOSITION, gridView.getFirstVisiblePosition());
}
}
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.abstractlistfragment, menu); inflater.inflate(R.menu.abstractlistfragment, menu);
if(gridViewUsesMultipleColumns) { if(recyclerView.isMultiColumnSupported()) {
if (PreferenceManager if (PreferenceManager
.getDefaultSharedPreferences(getActivity()) .getDefaultSharedPreferences(getActivity())
.getBoolean(Settings.KEY_PREF_SINGLE_COLUMN, .getBoolean(Settings.KEY_PREF_SINGLE_COLUMN,
Settings.DEFAULT_PREF_SINGLE_COLUMN)) { Settings.DEFAULT_PREF_SINGLE_COLUMN)) {
gridView.setNumColumns(1); recyclerView.setColumnCount(1);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
MenuItem item = menu.findItem(R.id.action_multi_single_columns); MenuItem item = menu.findItem(R.id.action_multi_single_columns);
item.setTitle(R.string.multi_column); item.setTitle(R.string.multi_column);
} }
} else { } else {
//Default number of columns for GridView is set to AUTO_FIT. //Disable menu item when mult-column is not supported
//When this leads to a single column it is not possible
//to switch to multiple columns. We therefore disable
//the menu item.
MenuItem item = menu.findItem(R.id.action_multi_single_columns); MenuItem item = menu.findItem(R.id.action_multi_single_columns);
item.setTitle(R.string.multi_column); item.setTitle(R.string.multi_column);
item.setEnabled(false); item.setEnabled(false);
@ -170,14 +131,14 @@ public abstract class AbstractListFragment extends Fragment implements
private void toggleAmountOfColumns(MenuItem item) { private void toggleAmountOfColumns(MenuItem item) {
SharedPreferences.Editor editor = PreferenceManager SharedPreferences.Editor editor = PreferenceManager
.getDefaultSharedPreferences(getActivity()).edit(); .getDefaultSharedPreferences(getActivity()).edit();
if (gridView.getNumColumns() == 1) { if (recyclerView.getColumnCount() == 1) {
editor.putBoolean(Settings.KEY_PREF_SINGLE_COLUMN, false); editor.putBoolean(Settings.KEY_PREF_SINGLE_COLUMN, false);
item.setTitle(R.string.single_column); item.setTitle(R.string.single_column);
gridView.setNumColumns(GridView.AUTO_FIT); recyclerView.setColumnCount(RecyclerViewEmptyViewSupport.AUTO_FIT);
} else { } else {
editor.putBoolean(Settings.KEY_PREF_SINGLE_COLUMN, true); editor.putBoolean(Settings.KEY_PREF_SINGLE_COLUMN, true);
item.setTitle(R.string.multi_column); item.setTitle(R.string.multi_column);
gridView.setNumColumns(1); recyclerView.setColumnCount(1);
} }
editor.apply(); editor.apply();
adapter.notifyDataSetChanged(); //force gridView to redraw adapter.notifyDataSetChanged(); //force gridView to redraw
@ -187,7 +148,7 @@ public abstract class AbstractListFragment extends Fragment implements
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
public BaseAdapter getAdapter() { public RecyclerView.Adapter getAdapter() {
return adapter; return adapter;
} }

View File

@ -48,8 +48,8 @@ import org.xbmc.kore.jsonrpc.method.Player;
import org.xbmc.kore.jsonrpc.type.ListType; import org.xbmc.kore.jsonrpc.type.ListType;
import org.xbmc.kore.jsonrpc.type.PlayerType; import org.xbmc.kore.jsonrpc.type.PlayerType;
import org.xbmc.kore.ui.generic.NavigationDrawerFragment; import org.xbmc.kore.ui.generic.NavigationDrawerFragment;
import org.xbmc.kore.ui.sections.remote.RemoteActivity;
import org.xbmc.kore.ui.generic.VolumeControllerDialogFragmentListener; import org.xbmc.kore.ui.generic.VolumeControllerDialogFragmentListener;
import org.xbmc.kore.ui.sections.remote.RemoteActivity;
import org.xbmc.kore.ui.widgets.MediaProgressIndicator; import org.xbmc.kore.ui.widgets.MediaProgressIndicator;
import org.xbmc.kore.ui.widgets.NowPlayingPanel; import org.xbmc.kore.ui.widgets.NowPlayingPanel;
import org.xbmc.kore.ui.widgets.VolumeLevelIndicator; import org.xbmc.kore.ui.widgets.VolumeLevelIndicator;
@ -58,8 +58,8 @@ import org.xbmc.kore.utils.SharedElementTransition;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
import org.xbmc.kore.utils.Utils; import org.xbmc.kore.utils.Utils;
import butterknife.ButterKnife;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife;
public abstract class BaseMediaActivity extends BaseActivity public abstract class BaseMediaActivity extends BaseActivity
implements HostConnectionObserver.ApplicationEventsObserver, implements HostConnectionObserver.ApplicationEventsObserver,
@ -141,7 +141,7 @@ public abstract class BaseMediaActivity extends BaseActivity
if (fragment == null) { if (fragment == null) {
fragment = createFragment(); fragment = createFragment();
if (Utils.isLollipopAndPreOreo()) { if (Utils.isLollipopOrLater()) {
fragment.setExitTransition(null); fragment.setExitTransition(null);
fragment.setReenterTransition(TransitionInflater fragment.setReenterTransition(TransitionInflater
.from(this) .from(this)
@ -154,7 +154,7 @@ public abstract class BaseMediaActivity extends BaseActivity
.commit(); .commit();
} }
if (Utils.isLollipopAndPreOreo()) { if (Utils.isLollipopOrLater()) {
sharedElementTransition.setupExitTransition(this, fragment); sharedElementTransition.setupExitTransition(this, fragment);
} }
@ -265,7 +265,7 @@ public abstract class BaseMediaActivity extends BaseActivity
FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction(); FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction();
// Set up transitions // Set up transitions
if (Utils.isLollipopAndPreOreo()) { if (Utils.isLollipopOrLater()) {
dataHolder.setPosterTransitionName(sharedImageView.getTransitionName()); dataHolder.setPosterTransitionName(sharedImageView.getTransitionName());
sharedElementTransition.setupEnterTransition(this, fragTrans, fragment, sharedImageView); sharedElementTransition.setupEnterTransition(this, fragTrans, fragment, sharedImageView);
} else { } else {

View File

@ -0,0 +1,92 @@
/*
* Copyright 2018 Martijn Brekhof. All rights reserved.
*
* 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 org.xbmc.kore.ui;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.view.View;
abstract public class RecyclerViewCursorAdapter extends RecyclerView.Adapter<RecyclerViewCursorAdapter.CursorViewHolder> {
private boolean dataValid;
private int rowIDColumn;
private Cursor cursor;
@Override
public void onBindViewHolder(CursorViewHolder holder, int position) {
if (!dataValid) {
throw new IllegalStateException("Cannot bind viewholder when cursor is in invalid state.");
}
if (!cursor.moveToPosition(position)) {
throw new IllegalStateException("Could not move cursor to position " + position + " when trying to bind viewholder");
}
holder.bindView(cursor);
}
@Override
public int getItemCount() {
if (dataValid) {
return cursor.getCount();
} else {
return 0;
}
}
@Override
public long getItemId(int position) {
if (!dataValid) {
throw new IllegalStateException("Cursor is in an invalid state.");
}
if (!cursor.moveToPosition(position)) {
throw new IllegalStateException("Could not move cursor to position " + position);
}
return cursor.getLong(rowIDColumn);
}
public void swapCursor(Cursor newCursor) {
if (newCursor == cursor) {
return;
}
if (newCursor != null) {
cursor = newCursor;
rowIDColumn = cursor.getColumnIndexOrThrow("_id");
dataValid = true;
notifyDataSetChanged();
} else {
notifyItemRangeRemoved(0, getItemCount());
cursor = null;
rowIDColumn = -1;
dataValid = false;
}
}
abstract public static class CursorViewHolder extends RecyclerView.ViewHolder {
public CursorViewHolder(View itemView) {
super(itemView);
itemView.setTag(this);
}
/**
* Called to update the content of {@link RecyclerView.ViewHolder#itemView} this holder holds.
*/
abstract public void bindView(Cursor cursor);
}
}

View File

@ -15,18 +15,15 @@
*/ */
package org.xbmc.kore.ui.sections.addon; package org.xbmc.kore.ui.sections.addon;
import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -38,10 +35,12 @@ import org.xbmc.kore.jsonrpc.method.Addons;
import org.xbmc.kore.jsonrpc.type.AddonType; import org.xbmc.kore.jsonrpc.type.AddonType;
import org.xbmc.kore.ui.AbstractInfoFragment; import org.xbmc.kore.ui.AbstractInfoFragment;
import org.xbmc.kore.ui.AbstractListFragment; import org.xbmc.kore.ui.AbstractListFragment;
import org.xbmc.kore.ui.viewgroups.RecyclerViewEmptyViewSupport;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
import org.xbmc.kore.utils.Utils; import org.xbmc.kore.utils.Utils;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@ -65,10 +64,10 @@ public class AddonListFragment extends AbstractListFragment {
private Handler callbackHandler = new Handler(); private Handler callbackHandler = new Handler();
@Override @Override
protected AdapterView.OnItemClickListener createOnItemClickListener() { protected RecyclerViewEmptyViewSupport.OnItemClickListener createOnItemClickListener() {
return new AdapterView.OnItemClickListener() { return new RecyclerViewEmptyViewSupport.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(View view, int position) {
// Get the movie id from the tag // Get the movie id from the tag
ViewHolder tag = (ViewHolder) view.getTag(); ViewHolder tag = (ViewHolder) view.getTag();
// Notify the activity // Notify the activity
@ -77,10 +76,9 @@ public class AddonListFragment extends AbstractListFragment {
}; };
} }
@Override @Override
protected BaseAdapter createAdapter() { protected RecyclerView.Adapter createAdapter() {
return new AddonsAdapter(getActivity(), R.layout.grid_item_addon); return new AddonsAdapter(getActivity());
} }
@Override @Override
@ -88,7 +86,7 @@ public class AddonListFragment extends AbstractListFragment {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(false); setHasOptionsMenu(false);
if (getAdapter().getCount() == 0) if (getAdapter().getItemCount() == 0)
callGetAddonsAndSetup(); callGetAddonsAndSetup();
} }
@ -172,7 +170,7 @@ public class AddonListFragment extends AbstractListFragment {
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
hideRefreshAnimation(); hideRefreshAnimation();
if (adapter.getCount() == 0) { if (adapter.getItemCount() == 0) {
getEmptyView().setText(R.string.no_addons_found_refresh); getEmptyView().setText(R.string.no_addons_found_refresh);
} }
} }
@ -190,15 +188,16 @@ public class AddonListFragment extends AbstractListFragment {
callbackHandler); callbackHandler);
} }
private class AddonsAdapter extends ArrayAdapter<AddonType.Details> { private static class AddonsAdapter extends RecyclerView.Adapter {
private HostManager hostManager; private HostManager hostManager;
private int artWidth, artHeight; private int artWidth, artHeight;
private String author; private Context context;
private String version;
public AddonsAdapter(Context context, int resource) { private ArrayList<AddonType.Details> items = new ArrayList<>();
super(context, resource);
public AddonsAdapter(Context context) {
this.context = context;
this.hostManager = HostManager.getInstance(context); this.hostManager = HostManager.getInstance(context);
// Get the art dimensions // Get the art dimensions
@ -207,63 +206,96 @@ public class AddonListFragment extends AbstractListFragment {
Resources resources = context.getResources(); Resources resources = context.getResources();
artWidth = resources.getDimensionPixelOffset(R.dimen.detail_poster_width_square); artWidth = resources.getDimensionPixelOffset(R.dimen.detail_poster_width_square);
artHeight = resources.getDimensionPixelOffset(R.dimen.detail_poster_height_square); artHeight = resources.getDimensionPixelOffset(R.dimen.detail_poster_height_square);
author = context.getString(R.string.author);
version = context.getString(R.string.version);
} }
/** {@inheritDoc} */
@TargetApi(21)
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (convertView == null) { View view = LayoutInflater.from(context)
convertView = LayoutInflater.from(getActivity()) .inflate(R.layout.grid_item_addon, parent, false);
.inflate(R.layout.grid_item_addon, parent, false);
// Setup View holder pattern return new ViewHolder(view, context, hostManager, artWidth, artHeight);
ViewHolder viewHolder = new ViewHolder(); }
viewHolder.titleView = (TextView)convertView.findViewById(R.id.title);
viewHolder.detailsView = (TextView)convertView.findViewById(R.id.details);
viewHolder.artView = (ImageView)convertView.findViewById(R.id.art);
convertView.setTag(viewHolder);
}
final ViewHolder viewHolder = (ViewHolder)convertView.getTag(); @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
AddonType.Details addonDetails = this.getItem(position); AddonType.Details addonDetails = this.getItem(position);
((ViewHolder) holder).onBind(addonDetails);
}
viewHolder.dataHolder.setTitle(addonDetails.name); @Override
viewHolder.dataHolder.setDescription(addonDetails.description); public int getItemCount() {
viewHolder.dataHolder.setUndertitle(addonDetails.summary); return items.size();
viewHolder.dataHolder.setFanArtUrl(addonDetails.fanart); }
viewHolder.dataHolder.setPosterUrl(addonDetails.thumbnail);
viewHolder.dataHolder.setDetails(author + " " + addonDetails.author + "\n" +
version + " " +addonDetails.version);
viewHolder.dataHolder.getBundle().putString(AddonInfoFragment.BUNDLE_KEY_ADDONID, addonDetails.addonid);
viewHolder.dataHolder.getBundle().putBoolean(AddonInfoFragment.BUNDLE_KEY_BROWSABLE,
AddonType.Types.XBMC_PYTHON_PLUGINSOURCE.equals(addonDetails.type));
viewHolder.titleView.setText(viewHolder.dataHolder.getTitle()); public void clear() {
viewHolder.detailsView.setText(addonDetails.summary); items.clear();
}
UIUtils.loadImageWithCharacterAvatar(getContext(), hostManager, public void add(AddonType.Details item) {
addonDetails.thumbnail, viewHolder.dataHolder.getTitle(), items.add(item);
viewHolder.artView, artWidth, artHeight); }
if(Utils.isLollipopOrLater()) { public AddonType.Details getItem(int position) {
viewHolder.artView.setTransitionName("a"+addonDetails.addonid); return items.get(position);
}
return convertView;
} }
} }
/** /**
* View holder pattern * View holder pattern
*/ */
public static class ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
TextView titleView; TextView titleView;
TextView detailsView; TextView detailsView;
ImageView artView; ImageView artView;
private static String author;
private static String version;
private HostManager hostManager;
int artWidth;
int artHeight;
Context context;
AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0); AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0);
ViewHolder(View itemView, Context context, HostManager hostManager, int artWidth, int artHeight) {
super(itemView);
this.context = context;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
if( author == null ) {
author = context.getString(R.string.author);
version = context.getString(R.string.version);
}
titleView = itemView.findViewById(R.id.title);
detailsView = itemView.findViewById(R.id.details);
artView = itemView.findViewById(R.id.art);
itemView.setTag(this);
}
public void onBind(AddonType.Details addonDetails) {
dataHolder.setTitle(addonDetails.name);
dataHolder.setDescription(addonDetails.description);
dataHolder.setUndertitle(addonDetails.summary);
dataHolder.setFanArtUrl(addonDetails.fanart);
dataHolder.setPosterUrl(addonDetails.thumbnail);
dataHolder.setDetails(author + " " + addonDetails.author + "\n" +
version + " " +addonDetails.version);
dataHolder.getBundle().putString(AddonInfoFragment.BUNDLE_KEY_ADDONID, addonDetails.addonid);
dataHolder.getBundle().putBoolean(AddonInfoFragment.BUNDLE_KEY_BROWSABLE,
AddonType.Types.XBMC_PYTHON_PLUGINSOURCE.equals(addonDetails.type));
titleView.setText(dataHolder.getTitle());
detailsView.setText(addonDetails.summary);
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
addonDetails.thumbnail, dataHolder.getTitle(),
artView, artWidth, artHeight);
if(Utils.isLollipopOrLater()) {
artView.setTransitionName("a"+addonDetails.addonid);
}
}
} }
} }

View File

@ -15,7 +15,6 @@
*/ */
package org.xbmc.kore.ui.sections.audio; package org.xbmc.kore.ui.sections.audio;
import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -25,6 +24,7 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import android.support.v4.app.Fragment;
import android.support.v4.content.CursorLoader; import android.support.v4.content.CursorLoader;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -33,7 +33,6 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
@ -48,6 +47,7 @@ import org.xbmc.kore.provider.MediaDatabase;
import org.xbmc.kore.service.library.LibrarySyncService; import org.xbmc.kore.service.library.LibrarySyncService;
import org.xbmc.kore.ui.AbstractCursorListFragment; import org.xbmc.kore.ui.AbstractCursorListFragment;
import org.xbmc.kore.ui.AbstractInfoFragment; import org.xbmc.kore.ui.AbstractInfoFragment;
import org.xbmc.kore.ui.RecyclerViewCursorAdapter;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.MediaPlayerUtils; import org.xbmc.kore.utils.MediaPlayerUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
@ -162,8 +162,8 @@ public class AlbumListFragment extends AbstractCursorListFragment {
} }
@Override @Override
protected CursorAdapter createAdapter() { protected RecyclerViewCursorAdapter createCursorAdapter() {
return new AlbumsAdapter(getActivity()); return new AlbumsAdapter(this);
} }
@Override @Override
@ -263,113 +263,119 @@ public class AlbumListFragment extends AbstractCursorListFragment {
int RATING = 7; int RATING = 7;
} }
private class AlbumsAdapter extends CursorAdapter { private static class AlbumsAdapter extends RecyclerViewCursorAdapter {
private HostManager hostManager; private HostManager hostManager;
private int artWidth, artHeight; private int artWidth, artHeight;
private Fragment fragment;
public AlbumsAdapter(Context context) { public AlbumsAdapter(Fragment fragment) {
super(context, null, 0); this.hostManager = HostManager.getInstance(fragment.getContext());
this.hostManager = HostManager.getInstance(context); this.fragment = fragment;
// Get the art dimensions // Get the art dimensions
// Use the same dimensions as in the details fragment, so that it hits Picasso's cache when // Use the same dimensions as in the details fragment, so that it hits Picasso's cache when
// the user transitions to that fragment, avoiding another call and imediatelly showing the image // the user transitions to that fragment, avoiding another call and imediatelly showing the image
Resources resources = context.getResources(); Resources resources = fragment.getContext().getResources();
artWidth = resources.getDimensionPixelOffset(R.dimen.detail_poster_width_square); artWidth = resources.getDimensionPixelOffset(R.dimen.detail_poster_width_square);
artHeight = resources.getDimensionPixelOffset(R.dimen.detail_poster_height_square); artHeight = resources.getDimensionPixelOffset(R.dimen.detail_poster_height_square);
} }
/** {@inheritDoc} */
@Override @Override
public View newView(Context context, final Cursor cursor, ViewGroup parent) { public CursorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(context) View view = LayoutInflater.from(fragment.getContext())
.inflate(R.layout.grid_item_album, parent, false); .inflate(R.layout.grid_item_album, parent, false);
// Setup View holder pattern return new ViewHolder(view, fragment.getContext(), hostManager, artWidth, artHeight,
ViewHolder viewHolder = new ViewHolder(); albumlistItemMenuClickListener);
viewHolder.titleView = (TextView)view.findViewById(R.id.title);
viewHolder.artistView = (TextView)view.findViewById(R.id.name);
viewHolder.genresView = (TextView)view.findViewById(R.id.genres);
viewHolder.artView = (ImageView)view.findViewById(R.id.art);
view.setTag(viewHolder);
return view;
} }
/** {@inheritDoc} */ private View.OnClickListener albumlistItemMenuClickListener = new View.OnClickListener() {
@TargetApi(21) @Override
@Override public void onClick(final View v) {
public void bindView(View view, Context context, Cursor cursor) { final ViewHolder viewHolder = (ViewHolder)v.getTag();
final ViewHolder viewHolder = (ViewHolder)view.getTag();
viewHolder.dataHolder.setId(cursor.getInt(AlbumListQuery.ALBUMID)); final PlaylistType.Item playListItem = new PlaylistType.Item();
viewHolder.dataHolder.setTitle(cursor.getString(AlbumListQuery.TITLE)); playListItem.albumid = viewHolder.dataHolder.getId();
viewHolder.dataHolder.setUndertitle(cursor.getString(AlbumListQuery.DISPLAYARTIST));
viewHolder.titleView.setText(viewHolder.dataHolder.getTitle()); final PopupMenu popupMenu = new PopupMenu(fragment.getContext(), v);
viewHolder.artistView.setText(viewHolder.dataHolder.getUnderTitle()); popupMenu.getMenuInflater().inflate(R.menu.musiclist_item, popupMenu.getMenu());
int year = cursor.getInt(AlbumListQuery.YEAR); popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
String genres = cursor.getString(AlbumListQuery.GENRE); @Override
String desc = (genres != null) ? public boolean onMenuItemClick(MenuItem item) {
((year > 0) ? genres + " | " + year : genres) : switch (item.getItemId()) {
String.valueOf(year); case R.id.action_play:
viewHolder.dataHolder.setDescription(desc); MediaPlayerUtils.play(fragment, playListItem);
viewHolder.genresView.setText(desc); return true;
case R.id.action_queue:
viewHolder.dataHolder.setPosterUrl(cursor.getString(AlbumListQuery.THUMBNAIL)); MediaPlayerUtils.queue(fragment, playListItem, PlaylistType.GetPlaylistsReturnType.AUDIO);
UIUtils.loadImageWithCharacterAvatar(context, hostManager, return true;
viewHolder.dataHolder.getPosterUrl(), }
viewHolder.dataHolder.getTitle(), return false;
viewHolder.artView, artWidth, artHeight); }
});
// For the popupmenu popupMenu.show();
ImageView contextMenu = (ImageView)view.findViewById(R.id.list_context_menu);
contextMenu.setTag(viewHolder);
contextMenu.setOnClickListener(albumlistItemMenuClickListener);
if (Utils.isLollipopOrLater()) {
viewHolder.artView.setTransitionName("al"+viewHolder.dataHolder.getId());
} }
} };
} }
/** /**
* View holder pattern * View holder pattern
*/ */
public static class ViewHolder { public static class ViewHolder extends RecyclerViewCursorAdapter.CursorViewHolder {
TextView titleView; TextView titleView;
TextView artistView; TextView artistView;
TextView genresView; TextView genresView;
ImageView artView; ImageView artView;
HostManager hostManager;
int artWidth;
int artHeight;
Context context;
AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0); AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0);
}
private View.OnClickListener albumlistItemMenuClickListener = new View.OnClickListener() { ViewHolder(View itemView, Context context, HostManager hostManager, int artWidth, int artHeight,
@Override View.OnClickListener contextMenuClickListener) {
public void onClick(final View v) { super(itemView);
final ViewHolder viewHolder = (ViewHolder)v.getTag(); this.context = context;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
titleView = itemView.findViewById(R.id.title);
artistView = itemView.findViewById(R.id.name);
genresView = itemView.findViewById(R.id.genres);
artView = itemView.findViewById(R.id.art);
final PlaylistType.Item playListItem = new PlaylistType.Item(); // For the popupmenu
playListItem.albumid = viewHolder.dataHolder.getId(); ImageView contextMenu = itemView.findViewById(R.id.list_context_menu);
contextMenu.setTag(this);
final PopupMenu popupMenu = new PopupMenu(getActivity(), v); contextMenu.setOnClickListener(contextMenuClickListener);
popupMenu.getMenuInflater().inflate(R.menu.musiclist_item, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_play:
MediaPlayerUtils.play(AlbumListFragment.this, playListItem);
return true;
case R.id.action_queue:
MediaPlayerUtils.queue(AlbumListFragment.this, playListItem, PlaylistType.GetPlaylistsReturnType.AUDIO);
return true;
}
return false;
}
});
popupMenu.show();
} }
}; @Override
public void bindView(Cursor cursor) {
dataHolder.setId(cursor.getInt(AlbumListQuery.ALBUMID));
dataHolder.setTitle(cursor.getString(AlbumListQuery.TITLE));
dataHolder.setUndertitle(cursor.getString(AlbumListQuery.DISPLAYARTIST));
titleView.setText(dataHolder.getTitle());
artistView.setText(dataHolder.getUnderTitle());
int year = cursor.getInt(AlbumListQuery.YEAR);
String genres = cursor.getString(AlbumListQuery.GENRE);
String desc = (genres != null) ?
((year > 0) ? genres + " | " + year : genres) :
String.valueOf(year);
dataHolder.setDescription(desc);
genresView.setText(desc);
dataHolder.setPosterUrl(cursor.getString(AlbumListQuery.THUMBNAIL));
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
dataHolder.getPosterUrl(),
dataHolder.getTitle(),
artView, artWidth, artHeight);
if (Utils.isLollipopOrLater()) {
artView.setTransitionName("al"+dataHolder.getId());
}
}
}
} }

View File

@ -15,20 +15,19 @@
*/ */
package org.xbmc.kore.ui.sections.audio; package org.xbmc.kore.ui.sections.audio;
import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import android.support.v4.app.Fragment;
import android.support.v4.content.CursorLoader; import android.support.v4.content.CursorLoader;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
@ -42,6 +41,7 @@ import org.xbmc.kore.provider.MediaDatabase;
import org.xbmc.kore.service.library.LibrarySyncService; import org.xbmc.kore.service.library.LibrarySyncService;
import org.xbmc.kore.ui.AbstractCursorListFragment; import org.xbmc.kore.ui.AbstractCursorListFragment;
import org.xbmc.kore.ui.AbstractInfoFragment; import org.xbmc.kore.ui.AbstractInfoFragment;
import org.xbmc.kore.ui.RecyclerViewCursorAdapter;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.MediaPlayerUtils; import org.xbmc.kore.utils.MediaPlayerUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
@ -72,8 +72,8 @@ public class ArtistListFragment extends AbstractCursorListFragment {
} }
@Override @Override
protected CursorAdapter createAdapter() { protected RecyclerViewCursorAdapter createCursorAdapter() {
return new ArtistsAdapter(getActivity()); return new ArtistsAdapter(this);
} }
@Override @Override
@ -135,105 +135,108 @@ public class ArtistListFragment extends AbstractCursorListFragment {
int FANART = 6; int FANART = 6;
} }
private class ArtistsAdapter extends CursorAdapter { private static class ArtistsAdapter extends RecyclerViewCursorAdapter {
private HostManager hostManager; private HostManager hostManager;
private int artWidth, artHeight; private int artWidth, artHeight;
Fragment fragment;
public ArtistsAdapter(Context context) { public ArtistsAdapter(Fragment fragment) {
super(context, null, 0); this.fragment = fragment;
this.hostManager = HostManager.getInstance(context); this.hostManager = HostManager.getInstance(fragment.getContext());
// Get the art dimensions // Get the art dimensions
Resources resources = context.getResources(); Resources resources = fragment.getContext().getResources();
artWidth = (int)(resources.getDimension(R.dimen.detail_poster_width_square)); artWidth = (int)(resources.getDimension(R.dimen.detail_poster_width_square));
artHeight = (int)(resources.getDimension(R.dimen.detail_poster_height_square)); artHeight = (int)(resources.getDimension(R.dimen.detail_poster_height_square));
} }
/** {@inheritDoc} */
@Override @Override
public View newView(Context context, final Cursor cursor, ViewGroup parent) { public CursorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(context) View view = LayoutInflater.from(fragment.getContext())
.inflate(R.layout.grid_item_artist, parent, false); .inflate(R.layout.grid_item_artist, parent, false);
// Setup View holder pattern return new ViewHolder(view, fragment.getContext(), hostManager, artWidth, artHeight, artistlistItemMenuClickListener);
ViewHolder viewHolder = new ViewHolder();
viewHolder.nameView = (TextView)view.findViewById(R.id.name);
viewHolder.genresView = (TextView)view.findViewById(R.id.genres);
viewHolder.artView = (ImageView)view.findViewById(R.id.art);
viewHolder.contextMenu = (ImageView)view.findViewById(R.id.list_context_menu);
view.setTag(viewHolder);
return view;
} }
/** {@inheritDoc} */ private View.OnClickListener artistlistItemMenuClickListener = new View.OnClickListener() {
@TargetApi(21) @Override
@Override public void onClick(final View v) {
public void bindView(View view, Context context, Cursor cursor) { final ViewHolder viewHolder = (ViewHolder)v.getTag();
final ViewHolder viewHolder = (ViewHolder)view.getTag();
// Save the movie id final PlaylistType.Item playListItem = new PlaylistType.Item();
viewHolder.dataHolder.setId(cursor.getInt(ArtistListQuery.ARTISTID)); playListItem.artistid = viewHolder.dataHolder.getId();
viewHolder.dataHolder.setTitle(cursor.getString(ArtistListQuery.ARTIST));
viewHolder.dataHolder.setUndertitle(cursor.getString(ArtistListQuery.GENRE));
viewHolder.dataHolder.setDescription(cursor.getString(ArtistListQuery.DESCRIPTION));
viewHolder.dataHolder.setFanArtUrl(cursor.getString(ArtistListQuery.FANART));
viewHolder.nameView.setText(cursor.getString(ArtistListQuery.ARTIST)); final PopupMenu popupMenu = new PopupMenu(fragment.getContext(), v);
viewHolder.genresView.setText(cursor.getString(ArtistListQuery.GENRE)); popupMenu.getMenuInflater().inflate(R.menu.musiclist_item, popupMenu.getMenu());
viewHolder.dataHolder.setPosterUrl(cursor.getString(ArtistListQuery.THUMBNAIL)); popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
UIUtils.loadImageWithCharacterAvatar(context, hostManager, public boolean onMenuItemClick(MenuItem item) {
viewHolder.dataHolder.getPosterUrl(), viewHolder.dataHolder.getTitle(), switch (item.getItemId()) {
viewHolder.artView, artWidth, artHeight); case R.id.action_play:
MediaPlayerUtils.play(fragment, playListItem);
viewHolder.contextMenu.setTag(viewHolder); return true;
viewHolder.contextMenu.setOnClickListener(artistlistItemMenuClickListener); case R.id.action_queue:
MediaPlayerUtils.queue(fragment, playListItem, PlaylistType.GetPlaylistsReturnType.AUDIO);
if (Utils.isLollipopOrLater()) { return true;
viewHolder.artView.setTransitionName("ar"+viewHolder.dataHolder.getId()); }
return false;
}
});
popupMenu.show();
} }
} };
} }
/** /**
* View holder pattern * View holder pattern
*/ */
public static class ViewHolder { public static class ViewHolder extends RecyclerViewCursorAdapter.CursorViewHolder {
TextView nameView; TextView nameView;
TextView genresView; TextView genresView;
ImageView artView; ImageView artView;
ImageView contextMenu; HostManager hostManager;
int artWidth;
int artHeight;
Context context;
AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0); AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0);
}
private View.OnClickListener artistlistItemMenuClickListener = new View.OnClickListener() { ViewHolder(View itemView, Context context, HostManager hostManager, int artWidth, int artHeight,
@Override View.OnClickListener contextMenuClickListener) {
public void onClick(final View v) { super(itemView);
final ViewHolder viewHolder = (ViewHolder)v.getTag(); this.context = context;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
nameView = itemView.findViewById(R.id.name);
genresView = itemView.findViewById(R.id.genres);
artView = itemView.findViewById(R.id.art);
final PlaylistType.Item playListItem = new PlaylistType.Item(); ImageView contextMenu = itemView.findViewById(R.id.list_context_menu);
playListItem.artistid = viewHolder.dataHolder.getId(); contextMenu.setTag(this);
contextMenu.setOnClickListener(contextMenuClickListener);
final PopupMenu popupMenu = new PopupMenu(getActivity(), v);
popupMenu.getMenuInflater().inflate(R.menu.musiclist_item, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_play:
MediaPlayerUtils.play(ArtistListFragment.this, playListItem);
return true;
case R.id.action_queue:
MediaPlayerUtils.queue(ArtistListFragment.this, playListItem, PlaylistType.GetPlaylistsReturnType.AUDIO);
return true;
}
return false;
}
});
popupMenu.show();
} }
};
@Override
public void bindView(Cursor cursor) {
dataHolder.setId(cursor.getInt(ArtistListQuery.ARTISTID));
dataHolder.setTitle(cursor.getString(ArtistListQuery.ARTIST));
dataHolder.setUndertitle(cursor.getString(ArtistListQuery.GENRE));
dataHolder.setDescription(cursor.getString(ArtistListQuery.DESCRIPTION));
dataHolder.setFanArtUrl(cursor.getString(ArtistListQuery.FANART));
nameView.setText(cursor.getString(ArtistListQuery.ARTIST));
genresView.setText(cursor.getString(ArtistListQuery.GENRE));
dataHolder.setPosterUrl(cursor.getString(ArtistListQuery.THUMBNAIL));
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
dataHolder.getPosterUrl(), dataHolder.getTitle(),
artView, artWidth, artHeight);
if (Utils.isLollipopOrLater()) {
artView.setTransitionName("ar"+dataHolder.getId());
}
}
}
} }

View File

@ -27,7 +27,6 @@ import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
@ -39,6 +38,7 @@ import org.xbmc.kore.jsonrpc.type.PlaylistType;
import org.xbmc.kore.provider.MediaContract; import org.xbmc.kore.provider.MediaContract;
import org.xbmc.kore.service.library.LibrarySyncService; import org.xbmc.kore.service.library.LibrarySyncService;
import org.xbmc.kore.ui.AbstractCursorListFragment; import org.xbmc.kore.ui.AbstractCursorListFragment;
import org.xbmc.kore.ui.RecyclerViewCursorAdapter;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.MediaPlayerUtils; import org.xbmc.kore.utils.MediaPlayerUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
@ -68,7 +68,7 @@ public class AudioGenresListFragment extends AbstractCursorListFragment {
} }
@Override @Override
protected CursorAdapter createAdapter() { protected RecyclerViewCursorAdapter createCursorAdapter() {
return new AudioGenresAdapter(getActivity()); return new AudioGenresAdapter(getActivity());
} }
@ -125,13 +125,12 @@ public class AudioGenresListFragment extends AbstractCursorListFragment {
final int THUMBNAIL = 3; final int THUMBNAIL = 3;
} }
private class AudioGenresAdapter extends CursorAdapter { private class AudioGenresAdapter extends RecyclerViewCursorAdapter {
private HostManager hostManager; private HostManager hostManager;
private int artWidth, artHeight; private int artWidth, artHeight;
public AudioGenresAdapter(Context context) { public AudioGenresAdapter(Context context) {
super(context, null, 0);
this.hostManager = HostManager.getInstance(context); this.hostManager = HostManager.getInstance(context);
// Get the art dimensions // Get the art dimensions
@ -142,52 +141,56 @@ public class AudioGenresListFragment extends AbstractCursorListFragment {
UIUtils.IMAGE_RESIZE_FACTOR); UIUtils.IMAGE_RESIZE_FACTOR);
} }
/** {@inheritDoc} */
@Override @Override
public View newView(Context context, final Cursor cursor, ViewGroup parent) { public CursorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(context) View view = LayoutInflater.from(getContext())
.inflate(R.layout.grid_item_audio_genre, parent, false); .inflate(R.layout.grid_item_audio_genre, parent, false);
// Setup View holder pattern return new ViewHolder(view, getContext(), hostManager, artWidth, artHeight, genrelistItemMenuClickListener);
ViewHolder viewHolder = new ViewHolder();
viewHolder.titleView = (TextView)view.findViewById(R.id.title);
viewHolder.artView = (ImageView)view.findViewById(R.id.art);
view.setTag(viewHolder);
return view;
}
/** {@inheritDoc} */
@Override
public void bindView(View view, Context context, Cursor cursor) {
final ViewHolder viewHolder = (ViewHolder)view.getTag();
viewHolder.genreId = cursor.getInt(AudioGenreListQuery.GENREID);
viewHolder.genreTitle = cursor.getString(AudioGenreListQuery.TITLE);
viewHolder.titleView.setText(viewHolder.genreTitle);
String thumbnail = cursor.getString(AudioGenreListQuery.THUMBNAIL);
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
thumbnail, viewHolder.genreTitle,
viewHolder.artView, artWidth, artHeight);
// For the popupmenu
ImageView contextMenu = (ImageView)view.findViewById(R.id.list_context_menu);
contextMenu.setTag(viewHolder);
contextMenu.setOnClickListener(genrelistItemMenuClickListener);
} }
} }
/** /**
* View holder pattern * View holder pattern
*/ */
private static class ViewHolder { private static class ViewHolder extends RecyclerViewCursorAdapter.CursorViewHolder {
TextView titleView; TextView titleView;
ImageView artView; ImageView artView;
HostManager hostManager;
int artWidth;
int artHeight;
Context context;
int genreId; int genreId;
String genreTitle; String genreTitle;
ViewHolder(View itemView, Context context, HostManager hostManager, int artWidth, int artHeight,
View.OnClickListener contextMenuClickListener) {
super(itemView);
this.context = context;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
titleView = itemView.findViewById(R.id.title);
artView = itemView.findViewById(R.id.art);
ImageView contextMenu = itemView.findViewById(R.id.list_context_menu);
contextMenu.setTag(this);
contextMenu.setOnClickListener(contextMenuClickListener);
}
@Override
public void bindView(Cursor cursor) {
genreId = cursor.getInt(AudioGenreListQuery.GENREID);
genreTitle = cursor.getString(AudioGenreListQuery.TITLE);
titleView.setText(genreTitle);
String thumbnail = cursor.getString(AudioGenreListQuery.THUMBNAIL);
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
thumbnail, genreTitle, artView, artWidth, artHeight);
}
} }
private View.OnClickListener genrelistItemMenuClickListener = new View.OnClickListener() { private View.OnClickListener genrelistItemMenuClickListener = new View.OnClickListener() {

View File

@ -15,7 +15,6 @@
*/ */
package org.xbmc.kore.ui.sections.audio; package org.xbmc.kore.ui.sections.audio;
import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
@ -27,7 +26,6 @@ import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@ -39,6 +37,7 @@ import org.xbmc.kore.provider.MediaDatabase;
import org.xbmc.kore.service.library.LibrarySyncService; import org.xbmc.kore.service.library.LibrarySyncService;
import org.xbmc.kore.ui.AbstractCursorListFragment; import org.xbmc.kore.ui.AbstractCursorListFragment;
import org.xbmc.kore.ui.AbstractInfoFragment; import org.xbmc.kore.ui.AbstractInfoFragment;
import org.xbmc.kore.ui.RecyclerViewCursorAdapter;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
import org.xbmc.kore.utils.Utils; import org.xbmc.kore.utils.Utils;
@ -68,7 +67,7 @@ public class MusicVideoListFragment extends AbstractCursorListFragment {
} }
@Override @Override
protected CursorAdapter createAdapter() { protected RecyclerViewCursorAdapter createCursorAdapter() {
return new MusicVideosAdapter(getActivity()); return new MusicVideosAdapter(getActivity());
} }
@ -137,13 +136,15 @@ public class MusicVideoListFragment extends AbstractCursorListFragment {
int PLOT = 9; int PLOT = 9;
} }
private static class MusicVideosAdapter extends CursorAdapter { private static class MusicVideosAdapter extends RecyclerViewCursorAdapter {
private HostManager hostManager; private HostManager hostManager;
private int artWidth, artHeight; private int artWidth, artHeight;
private Context context;
public MusicVideosAdapter(Context context) { public MusicVideosAdapter(Context context) {
super(context, null, 0); this.context = context;
this.hostManager = HostManager.getInstance(context); this.hostManager = HostManager.getInstance(context);
// Get the art dimensions // Get the art dimensions
@ -152,38 +153,50 @@ public class MusicVideoListFragment extends AbstractCursorListFragment {
artWidth = resources.getDimensionPixelOffset(R.dimen.detail_poster_height_square); artWidth = resources.getDimensionPixelOffset(R.dimen.detail_poster_height_square);
} }
/** {@inheritDoc} */
@Override @Override
public View newView(Context context, final Cursor cursor, ViewGroup parent) { public CursorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(context) View view = LayoutInflater.from(context)
.inflate(R.layout.grid_item_music_video, parent, false); .inflate(R.layout.grid_item_music_video, parent, false);
return new ViewHolder(view, context, hostManager, artWidth, artHeight);
// Setup View holder pattern
ViewHolder viewHolder = new ViewHolder();
viewHolder.titleView = (TextView)view.findViewById(R.id.title);
viewHolder.artistAlbumView = (TextView)view.findViewById(R.id.details);
viewHolder.durationGenresView = (TextView)view.findViewById(R.id.duration);
viewHolder.artView = (ImageView)view.findViewById(R.id.art);
view.setTag(viewHolder);
return view;
} }
}
/** {@inheritDoc} */ /**
@TargetApi(21) * View holder pattern
*/
public static class ViewHolder extends RecyclerViewCursorAdapter.CursorViewHolder {
TextView titleView;
TextView artistAlbumView;
TextView durationGenresView;
ImageView artView;
HostManager hostManager;
int artWidth;
int artHeight;
Context context;
AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0);
ViewHolder(View itemView, Context context, HostManager hostManager, int artWidth, int artHeight) {
super(itemView);
this.context = context;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
titleView = itemView.findViewById(R.id.title);
artistAlbumView = itemView.findViewById(R.id.details);
durationGenresView = itemView.findViewById(R.id.duration);
artView = itemView.findViewById(R.id.art);
}
@Override @Override
public void bindView(View view, Context context, Cursor cursor) { public void bindView(Cursor cursor) {
final ViewHolder viewHolder = (ViewHolder)view.getTag(); dataHolder.setId(cursor.getInt(MusicVideosListQuery.MUSICVIDEOID));
dataHolder.setTitle(cursor.getString(MusicVideosListQuery.TITLE));
// Save the movie id titleView.setText(dataHolder.getTitle());
viewHolder.dataHolder.setId(cursor.getInt(MusicVideosListQuery.MUSICVIDEOID));
viewHolder.dataHolder.setTitle(cursor.getString(MusicVideosListQuery.TITLE));
viewHolder.titleView.setText(viewHolder.dataHolder.getTitle());
String artistAlbum = cursor.getString(MusicVideosListQuery.ARTIST) + " | " + String artistAlbum = cursor.getString(MusicVideosListQuery.ARTIST) + " | " +
cursor.getString(MusicVideosListQuery.ALBUM); cursor.getString(MusicVideosListQuery.ALBUM);
viewHolder.artistAlbumView.setText(artistAlbum); artistAlbumView.setText(artistAlbum);
viewHolder.dataHolder.setUndertitle(artistAlbum); dataHolder.setUndertitle(artistAlbum);
int runtime = cursor.getInt(MusicVideosListQuery.RUNTIME); int runtime = cursor.getInt(MusicVideosListQuery.RUNTIME);
String genres = cursor.getString(MusicVideosListQuery.GENRES); String genres = cursor.getString(MusicVideosListQuery.GENRES);
@ -191,30 +204,17 @@ public class MusicVideoListFragment extends AbstractCursorListFragment {
runtime > 0 ? runtime > 0 ?
UIUtils.formatTime(runtime) + " | " + genres : UIUtils.formatTime(runtime) + " | " + genres :
genres; genres;
viewHolder.durationGenresView.setText(durationGenres); durationGenresView.setText(durationGenres);
viewHolder.dataHolder.setDetails(durationGenres); dataHolder.setDetails(durationGenres);
String posterUrl = cursor.getString(MusicVideosListQuery.THUMBNAIL); String posterUrl = cursor.getString(MusicVideosListQuery.THUMBNAIL);
viewHolder.dataHolder.setPosterUrl(posterUrl); dataHolder.setPosterUrl(posterUrl);
UIUtils.loadImageWithCharacterAvatar(context, hostManager, posterUrl UIUtils.loadImageWithCharacterAvatar(context, hostManager, posterUrl
, viewHolder.dataHolder.getTitle(), , dataHolder.getTitle(), artView, artWidth, artHeight);
viewHolder.artView, artWidth, artHeight);
if(Utils.isLollipopOrLater()) { if(Utils.isLollipopOrLater()) {
viewHolder.artView.setTransitionName("a"+viewHolder.dataHolder.getId()); artView.setTransitionName("a"+dataHolder.getId());
} }
} }
} }
/**
* View holder pattern
*/
public static class ViewHolder {
TextView titleView;
TextView artistAlbumView;
TextView durationGenresView;
ImageView artView;
AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0);
}
} }

View File

@ -34,7 +34,6 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
@ -48,6 +47,7 @@ import org.xbmc.kore.provider.MediaDatabase;
import org.xbmc.kore.provider.MediaProvider; import org.xbmc.kore.provider.MediaProvider;
import org.xbmc.kore.service.library.LibrarySyncService; import org.xbmc.kore.service.library.LibrarySyncService;
import org.xbmc.kore.ui.AbstractCursorListFragment; import org.xbmc.kore.ui.AbstractCursorListFragment;
import org.xbmc.kore.ui.RecyclerViewCursorAdapter;
import org.xbmc.kore.utils.FileDownloadHelper; import org.xbmc.kore.utils.FileDownloadHelper;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.MediaPlayerUtils; import org.xbmc.kore.utils.MediaPlayerUtils;
@ -67,7 +67,8 @@ public class SongsListFragment extends AbstractCursorListFragment {
private int artistId = -1; private int artistId = -1;
private int albumId = -1; private int albumId = -1;
private String albumTitle = ""; private static String albumTitle = "";
private Handler callbackHandler = new Handler(); private Handler callbackHandler = new Handler();
@ -96,11 +97,21 @@ public class SongsListFragment extends AbstractCursorListFragment {
protected String getListSyncType() { return LibrarySyncService.SYNC_ALL_MUSIC; } protected String getListSyncType() { return LibrarySyncService.SYNC_ALL_MUSIC; }
@Override @Override
protected CursorAdapter createAdapter() { protected RecyclerViewCursorAdapter createCursorAdapter() {
if (albumId != -1 ) { if (albumId != -1 ) {
return new AlbumSongsAdapter(getActivity()); return new AlbumSongsAdapter(getContext(), new View.OnClickListener() {
@Override
public void onClick(View v) {
showPopupMenu(v);
}
});
} else { } else {
return new SongsAdapter(getActivity()); return new SongsAdapter(getContext(), new View.OnClickListener() {
@Override
public void onClick(View v) {
showPopupMenu(v);
}
});
} }
} }
@ -234,15 +245,17 @@ public class SongsListFragment extends AbstractCursorListFragment {
int DISC = 7; int DISC = 7;
} }
private class SongsAdapter extends CursorAdapter { private static class SongsAdapter extends RecyclerViewCursorAdapter {
private HostManager hostManager; private HostManager hostManager;
private int artWidth, artHeight; private int artWidth, artHeight;
private Context context;
private View.OnClickListener contextMenuClickListener;
public SongsAdapter(Context context) { public SongsAdapter(Context context, View.OnClickListener contextMenuClickListener) {
super(context, null, 0);
this.hostManager = HostManager.getInstance(context); this.hostManager = HostManager.getInstance(context);
this.context = context;
this.contextMenuClickListener = contextMenuClickListener;
// Get the art dimensions // Get the art dimensions
// Use the same dimensions as in the details fragment, so that it hits Picasso's cache when // Use the same dimensions as in the details fragment, so that it hits Picasso's cache when
// the user transitions to that fragment, avoiding another call and imediatelly showing the image // the user transitions to that fragment, avoiding another call and imediatelly showing the image
@ -251,46 +264,103 @@ public class SongsListFragment extends AbstractCursorListFragment {
artHeight = resources.getDimensionPixelOffset(R.dimen.detail_poster_height_square); artHeight = resources.getDimensionPixelOffset(R.dimen.detail_poster_height_square);
} }
/** {@inheritDoc} */
@Override @Override
public View newView(Context context, Cursor cursor, ViewGroup parent) { public CursorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context) View view = LayoutInflater.from(context)
.inflate(R.layout.grid_item_song, parent, false); .inflate(R.layout.grid_item_song, parent, false);
// Setup View holder pattern return new SongViewHolder(view, context, hostManager, artWidth, artHeight,
ViewHolder viewHolder = new ViewHolder(); contextMenuClickListener);
viewHolder.title = (TextView)view.findViewById(R.id.title); }
viewHolder.details = (TextView)view.findViewById(R.id.details); }
viewHolder.art = (ImageView)view.findViewById(R.id.art);
viewHolder.artist = (TextView)view.findViewById(R.id.artist);
viewHolder.songInfo = new FileDownloadHelper.SongInfo();
viewHolder.contextMenu = (ImageView)view.findViewById(R.id.list_context_menu);
view.setTag(viewHolder); private static class AlbumSongsAdapter extends RecyclerViewCursorAdapter {
return view; private Context context;
private View.OnClickListener contextMenuClickListener;
public AlbumSongsAdapter(Context context, View.OnClickListener contextMenuClickListener) {
this.context = context;
this.contextMenuClickListener = contextMenuClickListener;
} }
/** {@inheritDoc} */
@Override @Override
public void bindView(View view, Context context, Cursor cursor) { public CursorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ViewHolder viewHolder = (ViewHolder)view.getTag(); View view = LayoutInflater.from(context)
.inflate(R.layout.list_item_song, parent, false);
return new AlbumViewHolder(view, contextMenuClickListener);
}
}
/**
* View holder pattern
*/
abstract static class ViewHolder extends RecyclerViewCursorAdapter.CursorViewHolder {
ImageView art;
TextView detailsTextView;
TextView artistTextView;
ImageView contextMenu;
FileDownloadHelper.SongInfo songInfo;
ViewHolder(View itemView, View.OnClickListener contextMenuClickListener) {
super(itemView);
art = itemView.findViewById(R.id.art);
artistTextView = itemView.findViewById(R.id.artist);
detailsTextView = itemView.findViewById(R.id.details);
contextMenu = itemView.findViewById(R.id.list_context_menu);
songInfo = new FileDownloadHelper.SongInfo();
contextMenu.setTag(this);
contextMenu.setOnClickListener(contextMenuClickListener);
}
@Override
public void bindView(Cursor cursor) {
songInfo.songId = cursor.getInt(SongsListQuery.SONGID);
songInfo.title = cursor.getString(SongsListQuery.TITLE);
songInfo.fileName = cursor.getString(SongsListQuery.FILE);
songInfo.track = cursor.getInt(SongsListQuery.TRACK);
}
}
public static class SongViewHolder extends ViewHolder {
HostManager hostManager;
int artWidth;
int artHeight;
Context context;
TextView titleTextView;
SongViewHolder(View itemView, Context context, HostManager hostManager,
int artWidth, int artHeight, View.OnClickListener contextMenuClickListener) {
super(itemView, contextMenuClickListener);
this.context = context;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
titleTextView = itemView.findViewById(R.id.title);
}
@Override
public void bindView(Cursor cursor) {
super.bindView(cursor);
String title = cursor.getString(SongsListQuery.TITLE); String title = cursor.getString(SongsListQuery.TITLE);
titleTextView.setText(title);
viewHolder.title.setText(title); artistTextView.setText(cursor.getString(SongsListQuery.SONGDISPLAYARTIST));
String artist = cursor.getString(SongsListQuery.SONGDISPLAYARTIST);
viewHolder.artist.setText(artist);
String albumTitle = cursor.getString(SongsListQuery.ALBUMTITLE); String albumTitle = cursor.getString(SongsListQuery.ALBUMTITLE);
int year = cursor.getInt(SongsListQuery.YEAR); int year = cursor.getInt(SongsListQuery.YEAR);
if (year > 0) { if (year > 0) {
setDetails(viewHolder.details, setDetails(detailsTextView,
albumTitle, albumTitle,
String.valueOf(year), String.valueOf(year),
cursor.getString(SongsListQuery.GENRE)); cursor.getString(SongsListQuery.GENRE));
} else { } else {
setDetails(viewHolder.details, setDetails(detailsTextView,
albumTitle, albumTitle,
cursor.getString(SongsListQuery.GENRE)); cursor.getString(SongsListQuery.GENRE));
} }
@ -298,101 +368,60 @@ public class SongsListFragment extends AbstractCursorListFragment {
String thumbnail = cursor.getString(SongsListQuery.THUMBNAIL); String thumbnail = cursor.getString(SongsListQuery.THUMBNAIL);
UIUtils.loadImageWithCharacterAvatar(context, hostManager, UIUtils.loadImageWithCharacterAvatar(context, hostManager,
thumbnail, title, thumbnail, title,
viewHolder.art, artWidth, artHeight); art, artWidth, artHeight);
}
viewHolder.songInfo.artist = artist; private void setDetails(TextView textView, String... elements) {
viewHolder.songInfo.album = albumTitle; if ((elements == null) || (elements.length < 1)) {
viewHolder.songInfo.songId = cursor.getInt(SongsListQuery.SONGID); return;
viewHolder.songInfo.title = cursor.getString(SongsListQuery.TITLE); }
viewHolder.songInfo.fileName = cursor.getString(SongsListQuery.FILE);
viewHolder.songInfo.track = cursor.getInt(SongsListQuery.TRACK);
// For the popupmenu ArrayList<String> details = new ArrayList<>();
viewHolder.contextMenu.setTag(viewHolder); for (int i = 0; i < elements.length; i++) {
viewHolder.contextMenu.setOnClickListener(new View.OnClickListener() { if (!TextUtils.isEmpty(elements[i]))
@Override details.add(elements[i]);
public void onClick(final View v) { }
showPopupMenu(v);
} textView.setText(TextUtils.join(" | ", details.toArray()));
});
} }
} }
private class AlbumSongsAdapter extends CursorAdapter { public static class AlbumViewHolder extends ViewHolder {
TextView trackNumberTextView;
TextView titleTextView;
public AlbumSongsAdapter(Context context) { AlbumViewHolder(View itemView, View.OnClickListener contextMenuClickListener) {
super(context, null, 0); super(itemView, contextMenuClickListener);
trackNumberTextView = itemView.findViewById(R.id.track_number);
titleTextView = itemView.findViewById(R.id.song_title);
} }
@Override @Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) { public void bindView(Cursor cursor) {
View view = LayoutInflater.from(context) super.bindView(cursor);
.inflate(R.layout.list_item_song, viewGroup, false);
// Setup View holder pattern
ViewHolder viewHolder = new ViewHolder();
viewHolder.trackNumber = (TextView)view.findViewById(R.id.track_number);
viewHolder.title = (TextView)view.findViewById(R.id.song_title);
viewHolder.details = (TextView)view.findViewById(R.id.details);
viewHolder.contextMenu = (ImageView)view.findViewById(R.id.list_context_menu);
viewHolder.songInfo = new FileDownloadHelper.SongInfo();
view.setTag(viewHolder); trackNumberTextView.setText(String.valueOf(songInfo.track));
return view;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
String artist = cursor.getString(AlbumSongsListQuery.ARTIST); String artist = cursor.getString(AlbumSongsListQuery.ARTIST);
ViewHolder vh = (ViewHolder) view.getTag(); titleTextView.setText(cursor.getString(AlbumSongsListQuery.TITLE));
vh.title.setText(cursor.getString(AlbumSongsListQuery.TITLE)); songInfo.artist = artist;
songInfo.album = albumTitle;
vh.songInfo.artist = artist;
vh.songInfo.album = albumTitle;
vh.songInfo.songId = cursor.getInt(SongsListQuery.SONGID);
vh.songInfo.title = cursor.getString(SongsListQuery.TITLE);
vh.songInfo.fileName = cursor.getString(SongsListQuery.FILE);
vh.songInfo.track = cursor.getInt(SongsListQuery.TRACK);
vh.trackNumber.setText(String.valueOf(vh.songInfo.track));
String duration = UIUtils.formatTime(cursor.getInt(AlbumSongsListQuery.DURATION)); String duration = UIUtils.formatTime(cursor.getInt(AlbumSongsListQuery.DURATION));
String detailsText = TextUtils.isEmpty(artist) ? duration : duration + " | " + artist; String detailsText = TextUtils.isEmpty(artist) ? duration : duration + " | " + artist;
vh.details.setText(detailsText); detailsTextView.setText(detailsText);
vh.contextMenu.setTag(vh);
vh.contextMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
showPopupMenu(v);
}
});
} }
} }
/**
* View holder pattern
*/
public static class ViewHolder {
ImageView art;
TextView title;
TextView details;
TextView artist;
TextView trackNumber;
ImageView contextMenu;
FileDownloadHelper.SongInfo songInfo;
}
private void showPopupMenu(View v) { private void showPopupMenu(View v) {
final ViewHolder viewHolder = (ViewHolder) v.getTag(); final ViewHolder viewHolder = (ViewHolder) v.getTag();
final PlaylistType.Item playListItem = new PlaylistType.Item(); final PlaylistType.Item playListItem = new PlaylistType.Item();
playListItem.songid = viewHolder.songInfo.songId; playListItem.songid = viewHolder.songInfo.songId;
final PopupMenu popupMenu = new PopupMenu(getActivity(), v); final PopupMenu popupMenu = new PopupMenu(getContext(), v);
popupMenu.getMenuInflater().inflate(R.menu.song_item, popupMenu.getMenu()); popupMenu.getMenuInflater().inflate(R.menu.song_item, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override @Override
@ -407,9 +436,9 @@ public class SongsListFragment extends AbstractCursorListFragment {
case R.id.download: case R.id.download:
ArrayList<FileDownloadHelper.SongInfo> songInfoList = new ArrayList<>(); ArrayList<FileDownloadHelper.SongInfo> songInfoList = new ArrayList<>();
songInfoList.add(viewHolder.songInfo); songInfoList.add(viewHolder.songInfo);
UIUtils.downloadSongs(getActivity(), UIUtils.downloadSongs(getContext(),
songInfoList, songInfoList,
HostManager.getInstance(getActivity()).getHostInfo(), HostManager.getInstance(getContext()).getHostInfo(),
callbackHandler); callbackHandler);
} }
return false; return false;
@ -417,19 +446,4 @@ public class SongsListFragment extends AbstractCursorListFragment {
}); });
popupMenu.show(); popupMenu.show();
} }
private void setDetails(TextView textView, String... elements) {
if ((elements == null) || (elements.length < 1)) {
return;
}
ArrayList<String> details = new ArrayList<>();
for (int i = 0; i < elements.length; i++) {
if (!TextUtils.isEmpty(elements[i]))
details.add(elements[i]);
}
textView.setText(TextUtils.join(" | ", details.toArray()));
}
} }

View File

@ -23,13 +23,11 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.StringRes; import android.support.annotation.StringRes;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -43,14 +41,14 @@ import org.xbmc.kore.jsonrpc.method.GUI;
import org.xbmc.kore.jsonrpc.type.FavouriteType; import org.xbmc.kore.jsonrpc.type.FavouriteType;
import org.xbmc.kore.jsonrpc.type.PlaylistType; import org.xbmc.kore.jsonrpc.type.PlaylistType;
import org.xbmc.kore.ui.AbstractListFragment; import org.xbmc.kore.ui.AbstractListFragment;
import org.xbmc.kore.ui.viewgroups.RecyclerViewEmptyViewSupport;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.MediaPlayerUtils; import org.xbmc.kore.utils.MediaPlayerUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import butterknife.ButterKnife;
public class FavouritesListFragment extends AbstractListFragment implements SwipeRefreshLayout.OnRefreshListener { public class FavouritesListFragment extends AbstractListFragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "FavouritesListFragment"; private static final String TAG = "FavouritesListFragment";
@ -63,7 +61,7 @@ public class FavouritesListFragment extends AbstractListFragment implements Swip
} }
@Override @Override
protected AdapterView.OnItemClickListener createOnItemClickListener() { protected RecyclerViewEmptyViewSupport.OnItemClickListener createOnItemClickListener() {
final ApiCallback<String> genericApiCallback = new ApiCallback<String>() { final ApiCallback<String> genericApiCallback = new ApiCallback<String>() {
@Override @Override
public void onSuccess(String result) { public void onSuccess(String result) {
@ -75,9 +73,9 @@ public class FavouritesListFragment extends AbstractListFragment implements Swip
Toast.makeText(getActivity(), description, Toast.LENGTH_SHORT).show(); Toast.makeText(getActivity(), description, Toast.LENGTH_SHORT).show();
} }
}; };
return new AdapterView.OnItemClickListener() { return new RecyclerViewEmptyViewSupport.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(View view, int position) {
final FavouritesAdapter favouritesAdapter = (FavouritesAdapter) getAdapter(); final FavouritesAdapter favouritesAdapter = (FavouritesAdapter) getAdapter();
final HostManager hostManager = HostManager.getInstance(getActivity()); final HostManager hostManager = HostManager.getInstance(getActivity());
@ -105,7 +103,7 @@ public class FavouritesListFragment extends AbstractListFragment implements Swip
} }
@Override @Override
protected BaseAdapter createAdapter() { protected RecyclerView.Adapter createAdapter() {
return new FavouritesAdapter(getActivity(), HostManager.getInstance(getActivity())); return new FavouritesAdapter(getActivity(), HostManager.getInstance(getActivity()));
} }
@ -126,7 +124,7 @@ public class FavouritesListFragment extends AbstractListFragment implements Swip
// To prevent the empty text from appearing on the first load, set it now // To prevent the empty text from appearing on the first load, set it now
getEmptyView().setText(getString(R.string.no_channels_found_refresh)); getEmptyView().setText(getString(R.string.no_channels_found_refresh));
setupFavouritesList(result.items); ((FavouritesAdapter) getAdapter()).setFavouriteItems(result.items);
hideRefreshAnimation(); hideRefreshAnimation();
} }
@ -143,25 +141,15 @@ public class FavouritesListFragment extends AbstractListFragment implements Swip
}, callbackHandler); }, callbackHandler);
} }
/** private static class FavouritesAdapter extends RecyclerView.Adapter {
* Called to set the GridView with the favourites that are coming from the host.
*
* @param favourites the favourites list that is supplied to the GridView.
*/
private void setupFavouritesList(List<FavouriteType.DetailsFavourite> favourites) {
final FavouritesAdapter favouritesAdapter = (FavouritesAdapter) getAdapter();
favouritesAdapter.clear();
favouritesAdapter.addAll(favourites);
favouritesAdapter.notifyDataSetChanged();
}
private static class FavouritesAdapter extends ArrayAdapter<FavouriteType.DetailsFavourite> {
private final HostManager hostManager; private final HostManager hostManager;
private final int artWidth, artHeight; private final int artWidth, artHeight;
private Context context;
private ArrayList<FavouriteType.DetailsFavourite> favouriteItems = new ArrayList<>();
FavouritesAdapter(@NonNull Context context, HostManager hostManager) { FavouritesAdapter(@NonNull Context context, HostManager hostManager) {
super(context, R.layout.grid_item_channel); this.context = context;
this.hostManager = hostManager; this.hostManager = hostManager;
Resources resources = context.getResources(); Resources resources = context.getResources();
artWidth = (int) (resources.getDimension(R.dimen.channellist_art_width) / artWidth = (int) (resources.getDimension(R.dimen.channellist_art_width) /
@ -170,23 +158,59 @@ public class FavouritesListFragment extends AbstractListFragment implements Swip
UIUtils.IMAGE_RESIZE_FACTOR); UIUtils.IMAGE_RESIZE_FACTOR);
} }
@NonNull public void setFavouriteItems(List<FavouriteType.DetailsFavourite> favouriteItems) {
this.favouriteItems.clear();
this.favouriteItems.addAll(favouriteItems);
notifyDataSetChanged();
}
public FavouriteType.DetailsFavourite getItem(int position) {
return favouriteItems.get(position);
}
@Override @Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (convertView == null) { View view = LayoutInflater.from(context).inflate(R.layout.grid_item_channel,
convertView = LayoutInflater.from(getContext()).inflate(R.layout.grid_item_channel, parent, false);
parent, false); return new ViewHolder(view, context, hostManager, artWidth, artHeight);
final FavouriteItemViewHolder vh = new FavouriteItemViewHolder(convertView); }
convertView.setTag(vh);
}
final FavouriteItemViewHolder vh = (FavouriteItemViewHolder) convertView.getTag(); @Override
final FavouriteType.DetailsFavourite favouriteDetail = getItem(position); public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((ViewHolder) holder).bindView(favouriteItems.get(position));
}
// We don't need the context menu here. @Override
vh.contextMenu.setVisibility(View.GONE); public int getItemCount() {
return favouriteItems.size();
}
}
vh.titleView.setText(favouriteDetail.title); private static class ViewHolder extends RecyclerView.ViewHolder {
final ImageView artView;
final TextView titleView;
final TextView detailView;
HostManager hostManager;
int artWidth;
int artHeight;
Context context;
ViewHolder(View itemView, Context context, HostManager hostManager, int artWidth, int artHeight) {
super(itemView);
this.context = context;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
artView = itemView.findViewById(R.id.art);
titleView = itemView.findViewById(R.id.title);
detailView = itemView.findViewById(R.id.details);
View contextMenu = itemView.findViewById(R.id.list_context_menu);
contextMenu.setVisibility(View.GONE);
}
void bindView(FavouriteType.DetailsFavourite favouriteDetail) {
titleView.setText(favouriteDetail.title);
@StringRes final int typeRes; @StringRes final int typeRes;
switch (favouriteDetail.type) { switch (favouriteDetail.type) {
@ -202,27 +226,11 @@ public class FavouritesListFragment extends AbstractListFragment implements Swip
default: default:
typeRes = R.string.unknown; typeRes = R.string.unknown;
} }
vh.detailView.setText(typeRes); detailView.setText(typeRes);
UIUtils.loadImageWithCharacterAvatar(getContext(), hostManager, UIUtils.loadImageWithCharacterAvatar(context, hostManager,
favouriteDetail.thumbnail, favouriteDetail.title, favouriteDetail.thumbnail, favouriteDetail.title,
vh.artView, artWidth, artHeight); artView, artWidth, artHeight);
return convertView;
}
}
private static class FavouriteItemViewHolder {
final ImageView artView;
final ImageView contextMenu;
final TextView titleView;
final TextView detailView;
FavouriteItemViewHolder(View v) {
artView = ButterKnife.findById(v, R.id.art);
contextMenu = ButterKnife.findById(v, R.id.list_context_menu);
titleView = ButterKnife.findById(v, R.id.title);
detailView = ButterKnife.findById(v, R.id.details);
} }
} }
} }

View File

@ -21,14 +21,12 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -45,6 +43,7 @@ import org.xbmc.kore.jsonrpc.type.ListType;
import org.xbmc.kore.jsonrpc.type.PlayerType; import org.xbmc.kore.jsonrpc.type.PlayerType;
import org.xbmc.kore.jsonrpc.type.PlaylistType; import org.xbmc.kore.jsonrpc.type.PlaylistType;
import org.xbmc.kore.ui.AbstractListFragment; import org.xbmc.kore.ui.AbstractListFragment;
import org.xbmc.kore.ui.viewgroups.RecyclerViewEmptyViewSupport;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
import org.xbmc.kore.utils.Utils; import org.xbmc.kore.utils.Utils;
@ -112,17 +111,17 @@ public class MediaFileListFragment extends AbstractListFragment {
} }
@Override @Override
protected AdapterView.OnItemClickListener createOnItemClickListener() { protected RecyclerViewEmptyViewSupport.OnItemClickListener createOnItemClickListener() {
return new AdapterView.OnItemClickListener() { return new RecyclerViewEmptyViewSupport.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(View view, int position) {
handleFileSelect(((MediaFileListAdapter) getAdapter()).getItem(position)); handleFileSelect(((MediaFileListAdapter) getAdapter()).getItem(position));
} }
}; };
} }
@Override @Override
protected BaseAdapter createAdapter() { protected RecyclerView.Adapter createAdapter() {
return new MediaFileListAdapter(getActivity(), R.layout.grid_item_file); return new MediaFileListAdapter(getActivity(), R.layout.grid_item_file);
} }
@ -211,7 +210,7 @@ public class MediaFileListFragment extends AbstractListFragment {
} }
public boolean atRootDirectory() { public boolean atRootDirectory() {
if (getAdapter().getCount() == 0) if (getAdapter().getItemCount() == 0)
return true; return true;
FileLocation fl = ((MediaFileListAdapter) getAdapter()).getItem(0); FileLocation fl = ((MediaFileListAdapter) getAdapter()).getItem(0);
if (fl == null) if (fl == null)
@ -500,11 +499,11 @@ public class MediaFileListFragment extends AbstractListFragment {
} }
private class MediaFileListAdapter extends BaseAdapter implements ListAdapter { private class MediaFileListAdapter extends RecyclerView.Adapter {
Context ctx; Context ctx;
int resource; int resource;
List<FileLocation> fileLocationItems = null; List<FileLocation> fileLocationItems;
int artWidth; int artWidth;
int artHeight; int artHeight;
@ -552,7 +551,7 @@ public class MediaFileListFragment extends AbstractListFragment {
} }
}; };
public MediaFileListAdapter(Context context, int resource) { MediaFileListAdapter(Context context, int resource) {
super(); super();
this.ctx = context; this.ctx = context;
this.resource = resource; this.resource = resource;
@ -580,20 +579,10 @@ public class MediaFileListFragment extends AbstractListFragment {
public List<FileLocation> getFileItemList() { public List<FileLocation> getFileItemList() {
if (fileLocationItems == null) if (fileLocationItems == null)
return new ArrayList<FileLocation>(); return new ArrayList<>();
return new ArrayList<FileLocation>(fileLocationItems); return new ArrayList<>(fileLocationItems);
} }
@Override
public int getCount() {
if (fileLocationItems == null) {
return 0;
} else {
return fileLocationItems.size();
}
}
@Override
public FileLocation getItem(int position) { public FileLocation getItem(int position) {
if (fileLocationItems == null) { if (fileLocationItems == null) {
return null; return null;
@ -602,74 +591,80 @@ public class MediaFileListFragment extends AbstractListFragment {
} }
} }
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(ctx)
.inflate(resource, parent, false);
return new ViewHolder(view, getContext(), hostManager, artWidth, artHeight, itemMenuClickListener);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
FileLocation fileLocation = this.getItem(position);
((ViewHolder) holder).bindView(fileLocation, position);
}
@Override @Override
public long getItemId(int position) { public long getItemId(int position) {
return position; return position;
} }
@Override @Override
public int getViewTypeCount () { public int getItemCount() {
return 1; if (fileLocationItems == null) {
} return 0;
/** {@inheritDoc} */
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(ctx)
.inflate(resource, parent, false);
// Setup View holder pattern
viewHolder = new ViewHolder();
viewHolder.art = (ImageView) convertView.findViewById(R.id.art);
viewHolder.title = (TextView) convertView.findViewById(R.id.title);
viewHolder.details = (TextView) convertView.findViewById(R.id.details);
viewHolder.contextMenu = (ImageView) convertView.findViewById(R.id.list_context_menu);
viewHolder.sizeDuration = (TextView) convertView.findViewById(R.id.size_duration);
convertView.setTag(viewHolder);
}
viewHolder = (ViewHolder) convertView.getTag();
FileLocation fileLocation = this.getItem(position);
// if (fileLocation.isDirectory) {
// viewHolder.title.setText(fileLocation.title);
// viewHolder.details.setText("");
// } else {
// viewHolder.title.setText("");
// viewHolder.details.setText(fileLocation.title);
// }
viewHolder.title.setText(fileLocation.title);
viewHolder.details.setText(fileLocation.details);
viewHolder.sizeDuration.setText(fileLocation.sizeDuration);
UIUtils.loadImageWithCharacterAvatar(getActivity(), hostManager,
fileLocation.artUrl, fileLocation.title,
viewHolder.art, artWidth, artHeight);
// For the popup menu
if (fileLocation.isDirectory) {
viewHolder.contextMenu.setVisibility(View.GONE);
} else { } else {
viewHolder.contextMenu.setVisibility(View.VISIBLE); return fileLocationItems.size();
viewHolder.contextMenu.setTag(position);
viewHolder.contextMenu.setOnClickListener(itemMenuClickListener);
} }
return convertView;
} }
} }
/** /**
* View holder pattern * View holder pattern
*/ */
private static class ViewHolder { private static class ViewHolder extends RecyclerView.ViewHolder {
ImageView art; ImageView art;
TextView title; TextView title;
TextView details; TextView details;
TextView sizeDuration; TextView sizeDuration;
ImageView contextMenu; ImageView contextMenu;
HostManager hostManager;
int artWidth;
int artHeight;
Context context;
ViewHolder(View itemView, Context context, HostManager hostManager, int artWidth, int artHeight,
View.OnClickListener itemMenuClickListener) {
super(itemView);
this.context = context;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
art = itemView.findViewById(R.id.art);
title = itemView.findViewById(R.id.title);
details = itemView.findViewById(R.id.details);
contextMenu = itemView.findViewById(R.id.list_context_menu);
sizeDuration = itemView.findViewById(R.id.size_duration);
contextMenu.setOnClickListener(itemMenuClickListener);
}
public void bindView(FileLocation fileLocation, int position) {
title.setText(fileLocation.title);
details.setText(fileLocation.details);
sizeDuration.setText(fileLocation.sizeDuration);
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
fileLocation.artUrl, fileLocation.title,
art, artWidth, artHeight);
// For the popup menu
if (fileLocation.isDirectory) {
contextMenu.setVisibility(View.GONE);
} else {
contextMenu.setVisibility(View.VISIBLE);
contextMenu.setTag(position);
}
}
} }
public static class FileLocation implements Parcelable { public static class FileLocation implements Parcelable {

View File

@ -15,7 +15,6 @@
*/ */
package org.xbmc.kore.ui.sections.video; package org.xbmc.kore.ui.sections.video;
import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -33,7 +32,6 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@ -45,7 +43,8 @@ import org.xbmc.kore.provider.MediaContract;
import org.xbmc.kore.provider.MediaDatabase; import org.xbmc.kore.provider.MediaDatabase;
import org.xbmc.kore.service.library.LibrarySyncService; import org.xbmc.kore.service.library.LibrarySyncService;
import org.xbmc.kore.ui.AbstractCursorListFragment; import org.xbmc.kore.ui.AbstractCursorListFragment;
import org.xbmc.kore.ui.AbstractInfoFragment; import org.xbmc.kore.ui.AbstractFragment;
import org.xbmc.kore.ui.RecyclerViewCursorAdapter;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
import org.xbmc.kore.utils.Utils; import org.xbmc.kore.utils.Utils;
@ -63,7 +62,7 @@ public class MovieListFragment extends AbstractCursorListFragment {
// Activity listener // Activity listener
private OnMovieSelectedListener listenerActivity; private OnMovieSelectedListener listenerActivity;
private boolean showWatchedStatus; private static boolean showWatchedStatus;
@Override @Override
protected String getListSyncType() { return LibrarySyncService.SYNC_ALL_MOVIES; } protected String getListSyncType() { return LibrarySyncService.SYNC_ALL_MOVIES; }
@ -77,7 +76,7 @@ public class MovieListFragment extends AbstractCursorListFragment {
} }
@Override @Override
protected CursorAdapter createAdapter() { protected RecyclerViewCursorAdapter createCursorAdapter() {
return new MoviesAdapter(getActivity()); return new MoviesAdapter(getActivity());
} }
@ -310,15 +309,13 @@ public class MovieListFragment extends AbstractCursorListFragment {
int PLAYCOUNT = 9; int PLAYCOUNT = 9;
} }
private class MoviesAdapter extends CursorAdapter { private class MoviesAdapter extends RecyclerViewCursorAdapter {
private HostManager hostManager; private HostManager hostManager;
private int artWidth, artHeight; private int artWidth, artHeight;
private int themeAccentColor; private int themeAccentColor;
public MoviesAdapter(Context context) { MoviesAdapter(Context context) {
super(context, null, 0);
// Get the default accent color // Get the default accent color
Resources.Theme theme = context.getTheme(); Resources.Theme theme = context.getTheme();
TypedArray styledAttributes = theme.obtainStyledAttributes(new int[] { TypedArray styledAttributes = theme.obtainStyledAttributes(new int[] {
@ -340,83 +337,90 @@ public class MovieListFragment extends AbstractCursorListFragment {
UIUtils.IMAGE_RESIZE_FACTOR); UIUtils.IMAGE_RESIZE_FACTOR);
} }
/** {@inheritDoc} */
@Override @Override
public View newView(Context context, final Cursor cursor, ViewGroup parent) { public CursorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(context) final View view = LayoutInflater.from(getContext())
.inflate(R.layout.grid_item_movie, parent, false); .inflate(R.layout.grid_item_movie, parent, false);
// Setup View holder pattern return new ViewHolder(view, getContext(), themeAccentColor, hostManager, artWidth, artHeight);
ViewHolder viewHolder = new ViewHolder();
viewHolder.titleView = (TextView)view.findViewById(R.id.title);
viewHolder.detailsView = (TextView)view.findViewById(R.id.details);
viewHolder.durationView = (TextView)view.findViewById(R.id.duration);
viewHolder.checkmarkView = (ImageView)view.findViewById(R.id.checkmark);
viewHolder.artView = (ImageView)view.findViewById(R.id.art);
view.setTag(viewHolder);
return view;
}
/** {@inheritDoc} */
@TargetApi(21)
@Override
public void bindView(View view, Context context, Cursor cursor) {
final ViewHolder viewHolder = (ViewHolder)view.getTag();
// Save the movie id
viewHolder.dataHolder.setId(cursor.getInt(MovieListQuery.MOVIEID));
viewHolder.dataHolder.setTitle(cursor.getString(MovieListQuery.TITLE));
viewHolder.dataHolder.setUndertitle(cursor.getString(MovieListQuery.TAGLINE));
int movieYear = cursor.getInt(MovieListQuery.YEAR);
viewHolder.dataHolder.setRating(cursor.getDouble(MovieListQuery.RATING));
viewHolder.dataHolder.setMaxRating(10);
viewHolder.titleView.setText(viewHolder.dataHolder.getTitle());
String genres = cursor.getString(MovieListQuery.GENRES);
String details = TextUtils.isEmpty(viewHolder.dataHolder.getUnderTitle()) ?
genres : viewHolder.dataHolder.getUnderTitle();
viewHolder.detailsView.setText(details);
int runtime = cursor.getInt(MovieListQuery.RUNTIME) / 60;
String duration = runtime > 0 ?
String.format(context.getString(R.string.minutes_abbrev), String.valueOf(runtime)) +
" | " + movieYear :
String.valueOf(movieYear);
viewHolder.durationView.setText(duration);
viewHolder.dataHolder.setDetails(duration + "\n" + details);
viewHolder.dataHolder.setPosterUrl(cursor.getString(MovieListQuery.THUMBNAIL));
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
viewHolder.dataHolder.getPosterUrl(),
viewHolder.dataHolder.getTitle(),
viewHolder.artView, artWidth, artHeight);
if (showWatchedStatus && (cursor.getInt(MovieListQuery.PLAYCOUNT) > 0)) {
viewHolder.checkmarkView.setVisibility(View.VISIBLE);
viewHolder.checkmarkView.setColorFilter(themeAccentColor);
} else {
viewHolder.checkmarkView.setVisibility(View.INVISIBLE);
}
if (Utils.isLollipopOrLater()) {
viewHolder.artView.setTransitionName("a" + viewHolder.dataHolder.getId());
}
} }
} }
/** /**
* View holder pattern * View holder pattern
*/ */
public static class ViewHolder { public static class ViewHolder extends RecyclerViewCursorAdapter.CursorViewHolder {
TextView titleView; TextView titleView;
TextView detailsView; TextView detailsView;
TextView durationView; TextView durationView;
ImageView checkmarkView; ImageView checkmarkView;
ImageView artView; ImageView artView;
HostManager hostManager;
int artWidth;
int artHeight;
Context context;
int themeAccentColor;
AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0); AbstractFragment.DataHolder dataHolder = new AbstractFragment.DataHolder(0);
ViewHolder(View itemView, Context context, int themeAccentColor,
HostManager hostManager,
int artWidth, int artHeight) {
super(itemView);
this.context = context;
this.themeAccentColor = themeAccentColor;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
titleView = itemView.findViewById(R.id.title);
detailsView = itemView.findViewById(R.id.details);
durationView = itemView.findViewById(R.id.duration);
checkmarkView = itemView.findViewById(R.id.checkmark);
artView = itemView.findViewById(R.id.art);
}
@Override
public void bindView(Cursor cursor) {
// Save the movie id
dataHolder.setId(cursor.getInt(MovieListQuery.MOVIEID));
dataHolder.setTitle(cursor.getString(MovieListQuery.TITLE));
dataHolder.setUndertitle(cursor.getString(MovieListQuery.TAGLINE));
int movieYear = cursor.getInt(MovieListQuery.YEAR);
dataHolder.setRating(cursor.getDouble(MovieListQuery.RATING));
dataHolder.setMaxRating(10);
titleView.setText(dataHolder.getTitle());
String genres = cursor.getString(MovieListQuery.GENRES);
String details = TextUtils.isEmpty(dataHolder.getUnderTitle()) ?
genres : dataHolder.getUnderTitle();
detailsView.setText(details);
int runtime = cursor.getInt(MovieListQuery.RUNTIME) / 60;
String duration = runtime > 0 ?
String.format(context.getString(R.string.minutes_abbrev), String.valueOf(runtime)) +
" | " + movieYear :
String.valueOf(movieYear);
durationView.setText(duration);
dataHolder.setDetails(duration + "\n" + details);
dataHolder.setPosterUrl(cursor.getString(MovieListQuery.THUMBNAIL));
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
dataHolder.getPosterUrl(),
dataHolder.getTitle(),
artView, artWidth, artHeight);
if (showWatchedStatus && (cursor.getInt(MovieListQuery.PLAYCOUNT) > 0)) {
checkmarkView.setVisibility(View.VISIBLE);
checkmarkView.setColorFilter(themeAccentColor);
} else {
checkmarkView.setVisibility(View.INVISIBLE);
}
if (Utils.isLollipopOrLater()) {
artView.setTransitionName("a" + dataHolder.getId());
}
}
} }
} }

View File

@ -47,8 +47,8 @@ import org.xbmc.kore.utils.UIUtils;
import java.util.List; import java.util.List;
import butterknife.ButterKnife;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder; import butterknife.Unbinder;
/** /**
@ -96,7 +96,7 @@ public class PVRChannelsListFragment extends Fragment
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_generic_media_list, container, false); ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_pvr_list, container, false);
unbinder = ButterKnife.bind(this, root); unbinder = ButterKnife.bind(this, root);
if (savedInstanceState != null) { if (savedInstanceState != null) {

View File

@ -42,8 +42,8 @@ import org.xbmc.kore.utils.UIUtils;
import java.util.List; import java.util.List;
import butterknife.ButterKnife;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder; import butterknife.Unbinder;
/** /**
@ -75,7 +75,7 @@ public class PVRRecordingsListFragment extends Fragment
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_generic_media_list, container, false); ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_pvr_list, container, false);
unbinder = ButterKnife.bind(this, root); unbinder = ButterKnife.bind(this, root);
hostManager = HostManager.getInstance(getActivity()); hostManager = HostManager.getInstance(getActivity());

View File

@ -33,7 +33,6 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
@ -46,7 +45,8 @@ import org.xbmc.kore.jsonrpc.type.PlaylistType;
import org.xbmc.kore.provider.MediaContract; import org.xbmc.kore.provider.MediaContract;
import org.xbmc.kore.service.library.LibrarySyncService; import org.xbmc.kore.service.library.LibrarySyncService;
import org.xbmc.kore.ui.AbstractCursorListFragment; import org.xbmc.kore.ui.AbstractCursorListFragment;
import org.xbmc.kore.ui.AbstractInfoFragment; import org.xbmc.kore.ui.AbstractFragment;
import org.xbmc.kore.ui.RecyclerViewCursorAdapter;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.MediaPlayerUtils; import org.xbmc.kore.utils.MediaPlayerUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
@ -114,9 +114,8 @@ public class TVShowEpisodeListFragment extends AbstractCursorListFragment {
listenerActivity.onEpisodeSelected(tvshowId, tag); listenerActivity.onEpisodeSelected(tvshowId, tag);
} }
@Override @Override
protected CursorAdapter createAdapter() { protected RecyclerViewCursorAdapter createCursorAdapter() {
return new SeasonsEpisodesAdapter(getActivity()); return new SeasonsEpisodesAdapter(getActivity());
} }
@ -137,7 +136,6 @@ public class TVShowEpisodeListFragment extends AbstractCursorListFragment {
EpisodesListQuery.PROJECTION, selection.toString(), null, EpisodesListQuery.SORT); EpisodesListQuery.PROJECTION, selection.toString(), null, EpisodesListQuery.SORT);
} }
@Override @Override
public void onAttach(Context context) { public void onAttach(Context context) {
super.onAttach(context); super.onAttach(context);
@ -218,25 +216,23 @@ public class TVShowEpisodeListFragment extends AbstractCursorListFragment {
} }
private class SeasonsEpisodesAdapter extends CursorAdapter { private class SeasonsEpisodesAdapter extends RecyclerViewCursorAdapter {
private HostManager hostManager;
private int artWidth, artHeight;
private int themeAccentColor; private int themeAccentColor;
private HostManager hostManager;
private int artWidth;
private int artHeight;
public SeasonsEpisodesAdapter(Context context) { SeasonsEpisodesAdapter(Context context) {
super(context, null, 0);
// Get the default accent color // Get the default accent color
Resources.Theme theme = context.getTheme(); Resources.Theme theme = context.getTheme();
TypedArray styledAttributes = theme.obtainStyledAttributes(new int[] { TypedArray styledAttributes = theme.obtainStyledAttributes(new int[] {
R.attr.colorAccent R.attr.colorAccent
}); });
themeAccentColor = styledAttributes.getColor(styledAttributes.getIndex(0), getResources().getColor(R.color.accent_default)); themeAccentColor = styledAttributes.getColor(styledAttributes.getIndex(0), getResources().getColor(R.color.accent_default));
styledAttributes.recycle(); styledAttributes.recycle();
this.hostManager = HostManager.getInstance(context); hostManager = HostManager.getInstance(context);
// Get the art dimensions // Get the art dimensions
Resources resources = context.getResources(); Resources resources = context.getResources();
@ -246,77 +242,84 @@ public class TVShowEpisodeListFragment extends AbstractCursorListFragment {
UIUtils.IMAGE_RESIZE_FACTOR); UIUtils.IMAGE_RESIZE_FACTOR);
} }
/** {@inheritDoc} */
@Override @Override
public View newView(Context context, final Cursor cursor, ViewGroup parent) { public RecyclerViewCursorAdapter.CursorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(context) View view = LayoutInflater.from(getActivity())
.inflate(R.layout.list_item_episode, parent, false); .inflate(R.layout.list_item_episode, parent, false);
return new ViewHolder(view, getActivity(), themeAccentColor,
// Setup View holder pattern contextlistItemMenuClickListener, hostManager,
ViewHolder viewHolder = new ViewHolder(); artWidth, artHeight);
viewHolder.titleView = (TextView)view.findViewById(R.id.title);
viewHolder.detailsView = (TextView)view.findViewById(R.id.details);
viewHolder.episodenumberView = (TextView)view.findViewById(R.id.episode_number);
viewHolder.contextMenuView = (ImageView)view.findViewById(R.id.list_context_menu);
viewHolder.checkmarkView = (ImageView)view.findViewById(R.id.checkmark);
viewHolder.artView = (ImageView)view.findViewById(R.id.art);
view.setTag(viewHolder);
return view;
}
/** {@inheritDoc} */
@TargetApi(21)
@Override
public void bindView(View view, Context context, Cursor cursor) {
final ViewHolder viewHolder = (ViewHolder)view.getTag();
// Save the episode id
viewHolder.dataHolder.setId(cursor.getInt(EpisodesListQuery.EPISODEID));
viewHolder.dataHolder.setTitle(cursor.getString(EpisodesListQuery.TITLE));
viewHolder.episodenumberView.setText(
String.format(context.getString(R.string.episode_number),
cursor.getInt(EpisodesListQuery.EPISODE)));
int runtime = cursor.getInt(EpisodesListQuery.RUNTIME) / 60;
String duration = runtime > 0 ?
String.format(context.getString(R.string.minutes_abbrev), String.valueOf(runtime)) +
" | " + cursor.getString(EpisodesListQuery.FIRSTAIRED) :
cursor.getString(EpisodesListQuery.FIRSTAIRED);
viewHolder.titleView.setText(cursor.getString(EpisodesListQuery.TITLE));
viewHolder.detailsView.setText(duration);
if (cursor.getInt(EpisodesListQuery.PLAYCOUNT) > 0) {
viewHolder.checkmarkView.setVisibility(View.VISIBLE);
viewHolder.checkmarkView.setColorFilter(themeAccentColor);
} else {
viewHolder.checkmarkView.setVisibility(View.INVISIBLE);
}
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
cursor.getString(EpisodesListQuery.THUMBNAIL),
viewHolder.dataHolder.getTitle(),
viewHolder.artView, artWidth, artHeight);
// For the popupmenu
ImageView contextMenu = (ImageView)view.findViewById(R.id.list_context_menu);
contextMenu.setTag(viewHolder);
contextMenu.setOnClickListener(contextlistItemMenuClickListener);
} }
} }
/** /**
* View holder pattern, only for episodes * View holder pattern, only for episodes
*/ */
public static class ViewHolder { static class ViewHolder extends RecyclerViewCursorAdapter.CursorViewHolder {
TextView titleView; TextView titleView;
TextView detailsView; TextView detailsView;
TextView episodenumberView; TextView episodenumberView;
ImageView contextMenuView; ImageView contextMenuView;
ImageView checkmarkView; ImageView checkmarkView;
ImageView artView; ImageView artView;
HostManager hostManager;
int artWidth;
int artHeight;
Context context;
int themeAccentColor;
AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0); AbstractFragment.DataHolder dataHolder = new AbstractFragment.DataHolder(0);
ViewHolder(View itemView, Context context, int themeAccentColor,
View.OnClickListener contextlistItemMenuClickListener,
HostManager hostManager,
int artWidth, int artHeight) {
super(itemView);
this.context = context;
this.themeAccentColor = themeAccentColor;
this.hostManager = hostManager;
this.artWidth = artWidth;
this.artHeight = artHeight;
titleView = itemView.findViewById(R.id.title);
detailsView = itemView.findViewById(R.id.details);
episodenumberView = itemView.findViewById(R.id.episode_number);
contextMenuView = itemView.findViewById(R.id.list_context_menu);
checkmarkView = itemView.findViewById(R.id.checkmark);
artView = itemView.findViewById(R.id.art);
contextMenuView.setOnClickListener(contextlistItemMenuClickListener);
}
@Override
public void bindView(Cursor cursor) {
// Save the episode id
dataHolder.setId(cursor.getInt(EpisodesListQuery.EPISODEID));
dataHolder.setTitle(cursor.getString(EpisodesListQuery.TITLE));
episodenumberView.setText(
String.format(context.getString(R.string.episode_number),
cursor.getInt(EpisodesListQuery.EPISODE)));
int runtime = cursor.getInt(EpisodesListQuery.RUNTIME) / 60;
String duration = runtime > 0 ?
String.format(context.getString(R.string.minutes_abbrev), String.valueOf(runtime)) +
" | " + cursor.getString(EpisodesListQuery.FIRSTAIRED) :
cursor.getString(EpisodesListQuery.FIRSTAIRED);
titleView.setText(cursor.getString(EpisodesListQuery.TITLE));
detailsView.setText(duration);
if (cursor.getInt(EpisodesListQuery.PLAYCOUNT) > 0) {
checkmarkView.setVisibility(View.VISIBLE);
checkmarkView.setColorFilter(themeAccentColor);
} else {
checkmarkView.setVisibility(View.INVISIBLE);
}
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
cursor.getString(EpisodesListQuery.THUMBNAIL),
dataHolder.getTitle(),
artView, artWidth, artHeight);
contextMenuView.setTag(this);
}
} }
private View.OnClickListener contextlistItemMenuClickListener = new View.OnClickListener() { private View.OnClickListener contextlistItemMenuClickListener = new View.OnClickListener() {

View File

@ -15,7 +15,6 @@
*/ */
package org.xbmc.kore.ui.sections.video; package org.xbmc.kore.ui.sections.video;
import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -34,7 +33,6 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
@ -48,6 +46,7 @@ import org.xbmc.kore.provider.MediaDatabase;
import org.xbmc.kore.service.library.LibrarySyncService; import org.xbmc.kore.service.library.LibrarySyncService;
import org.xbmc.kore.ui.AbstractCursorListFragment; import org.xbmc.kore.ui.AbstractCursorListFragment;
import org.xbmc.kore.ui.AbstractInfoFragment; import org.xbmc.kore.ui.AbstractInfoFragment;
import org.xbmc.kore.ui.RecyclerViewCursorAdapter;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.UIUtils; import org.xbmc.kore.utils.UIUtils;
import org.xbmc.kore.utils.Utils; import org.xbmc.kore.utils.Utils;
@ -65,7 +64,7 @@ public class TVShowListFragment extends AbstractCursorListFragment {
// Activity listener // Activity listener
private OnTVShowSelectedListener listenerActivity; private OnTVShowSelectedListener listenerActivity;
private boolean showWatchedStatus; private static boolean showWatchedStatus;
@Override @Override
protected String getListSyncType() { return LibrarySyncService.SYNC_ALL_TVSHOWS; } protected String getListSyncType() { return LibrarySyncService.SYNC_ALL_TVSHOWS; }
@ -79,7 +78,7 @@ public class TVShowListFragment extends AbstractCursorListFragment {
} }
@Override @Override
protected CursorAdapter createAdapter() { protected RecyclerViewCursorAdapter createCursorAdapter() {
return new TVShowsAdapter(getActivity()); return new TVShowsAdapter(getActivity());
} }
@ -309,7 +308,7 @@ public class TVShowListFragment extends AbstractCursorListFragment {
int GENRES = 13; int GENRES = 13;
} }
private class TVShowsAdapter extends CursorAdapter { private class TVShowsAdapter extends RecyclerViewCursorAdapter {
private HostManager hostManager; private HostManager hostManager;
private int artWidth, artHeight; private int artWidth, artHeight;
@ -317,8 +316,6 @@ public class TVShowListFragment extends AbstractCursorListFragment {
inProgressColor, finishedColor; inProgressColor, finishedColor;
public TVShowsAdapter(Context context) { public TVShowsAdapter(Context context) {
super(context, null, 0);
// Get the default accent color // Get the default accent color
Resources.Theme theme = context.getTheme(); Resources.Theme theme = context.getTheme();
TypedArray styledAttributes = theme.obtainStyledAttributes(new int[] { TypedArray styledAttributes = theme.obtainStyledAttributes(new int[] {
@ -344,82 +341,98 @@ public class TVShowListFragment extends AbstractCursorListFragment {
UIUtils.IMAGE_RESIZE_FACTOR); UIUtils.IMAGE_RESIZE_FACTOR);
} }
/** {@inheritDoc} */
@Override @Override
public View newView(Context context, final Cursor cursor, ViewGroup parent) { public CursorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(context) final View view = LayoutInflater.from(getContext())
.inflate(R.layout.grid_item_tvshow, parent, false); .inflate(R.layout.grid_item_tvshow, parent, false);
// Setup View holder pattern // Setup View holder pattern
ViewHolder viewHolder = new ViewHolder(); ViewHolder viewHolder = new ViewHolder(view, getContext(),
viewHolder.titleView = (TextView)view.findViewById(R.id.title); themeAccentColor, inProgressColor, finishedColor,
viewHolder.detailsView = (TextView)view.findViewById(R.id.details); hostManager,
viewHolder.premieredView = (TextView)view.findViewById(R.id.premiered); artWidth, artHeight);
viewHolder.artView = (ImageView)view.findViewById(R.id.art);
viewHolder.watchedProgressView = (ProgressBar)view.findViewById(R.id.tv_shows_progress_bar);
view.setTag(viewHolder); return viewHolder;
return view;
}
/** {@inheritDoc} */
@TargetApi(21)
@Override
public void bindView(View view, Context context, Cursor cursor) {
final ViewHolder vh = (ViewHolder)view.getTag();
// Save the movie id
vh.dataHolder.setId(cursor.getInt(TVShowListQuery.TVSHOWID));
vh.dataHolder.setTitle(cursor.getString(TVShowListQuery.TITLE));
vh.dataHolder.setDescription(cursor.getString(TVShowListQuery.PLOT));
vh.dataHolder.setRating(cursor.getInt(TVShowListQuery.RATING));
int numEpisodes = cursor.getInt(TVShowListQuery.EPISODE);
int watchedEpisodes = cursor.getInt(TVShowListQuery.WATCHEDEPISODES);
vh.titleView.setText(vh.dataHolder.getTitle());
String details = String.format(context.getString(R.string.num_episodes),
numEpisodes, numEpisodes - watchedEpisodes);
vh.detailsView.setText(details);
vh.dataHolder.setUndertitle(details);
String premiered = String.format(context.getString(R.string.premiered),
cursor.getString(TVShowListQuery.PREMIERED));
vh.premieredView.setText(premiered);
vh.dataHolder.setDetails(premiered);
vh.dataHolder.setPosterUrl(cursor.getString(TVShowListQuery.THUMBNAIL));
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
vh.dataHolder.getPosterUrl(),
vh.dataHolder.getTitle(),
vh.artView, artWidth, artHeight);
if (showWatchedStatus) {
vh.watchedProgressView.setVisibility(View.VISIBLE);
vh.watchedProgressView.setMax(numEpisodes);
vh.watchedProgressView.setProgress(watchedEpisodes);
} else {
vh.watchedProgressView.setVisibility(View.INVISIBLE);
}
if (Utils.isLollipopOrLater()) {
if (showWatchedStatus) {
int watchedColor = (numEpisodes - watchedEpisodes == 0)? finishedColor : inProgressColor;
vh.watchedProgressView.setProgressTintList(ColorStateList.valueOf(watchedColor));
}
vh.artView.setTransitionName("a" + vh.dataHolder.getId());
}
} }
} }
/** /**
* View holder pattern * View holder pattern
*/ */
public static class ViewHolder { public static class ViewHolder extends RecyclerViewCursorAdapter.CursorViewHolder {
TextView titleView; TextView titleView;
TextView detailsView; TextView detailsView;
TextView premieredView; TextView premieredView;
ImageView artView; ImageView artView;
ProgressBar watchedProgressView; ProgressBar watchedProgressView;
Context context;
int themeAccentColor, inProgressColor, finishedColor;
HostManager hostManager;
int artWidth;
int artHeight;
AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0); AbstractInfoFragment.DataHolder dataHolder = new AbstractInfoFragment.DataHolder(0);
ViewHolder(View itemView, Context context,
int themeAccentColor, int inProgressColor, int finishedColor,
HostManager hostManager,
int artWidth, int artHeight) {
super(itemView);
this.hostManager = hostManager;
this.context = context;
this.artHeight = artHeight;
this.artWidth = artWidth;
this.themeAccentColor = themeAccentColor;
this.inProgressColor = inProgressColor;
this.finishedColor = finishedColor;
titleView = itemView.findViewById(R.id.title);
detailsView = itemView.findViewById(R.id.details);
premieredView = itemView.findViewById(R.id.premiered);
artView = itemView.findViewById(R.id.art);
watchedProgressView = itemView.findViewById(R.id.tv_shows_progress_bar);
}
@Override
public void bindView(Cursor cursor) {
// Save the movie id
dataHolder.setId(cursor.getInt(TVShowListQuery.TVSHOWID));
dataHolder.setTitle(cursor.getString(TVShowListQuery.TITLE));
dataHolder.setDescription(cursor.getString(TVShowListQuery.PLOT));
dataHolder.setRating(cursor.getInt(TVShowListQuery.RATING));
int numEpisodes = cursor.getInt(TVShowListQuery.EPISODE);
int watchedEpisodes = cursor.getInt(TVShowListQuery.WATCHEDEPISODES);
titleView.setText(dataHolder.getTitle());
String details = String.format(context.getString(R.string.num_episodes),
numEpisodes, numEpisodes - watchedEpisodes);
detailsView.setText(details);
dataHolder.setUndertitle(details);
String premiered = String.format(context.getString(R.string.premiered),
cursor.getString(TVShowListQuery.PREMIERED));
premieredView.setText(premiered);
dataHolder.setDetails(premiered);
dataHolder.setPosterUrl(cursor.getString(TVShowListQuery.THUMBNAIL));
UIUtils.loadImageWithCharacterAvatar(context, hostManager,
dataHolder.getPosterUrl(),
dataHolder.getTitle(),
artView, artWidth, artHeight);
if (showWatchedStatus) {
watchedProgressView.setVisibility(View.VISIBLE);
watchedProgressView.setMax(numEpisodes);
watchedProgressView.setProgress(watchedEpisodes);
} else {
watchedProgressView.setVisibility(View.INVISIBLE);
}
if (Utils.isLollipopOrLater()) {
if (showWatchedStatus) {
int watchedColor = (numEpisodes - watchedEpisodes == 0)? finishedColor : inProgressColor;
watchedProgressView.setProgressTintList(ColorStateList.valueOf(watchedColor));
}
artView.setTransitionName("a" + dataHolder.getId());
}
}
} }
} }

View File

@ -0,0 +1,168 @@
/*
* Copyright 2018 Martijn Brekhof. All rights reserved.
*
* 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 org.xbmc.kore.ui.viewgroups;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
/**
* <p>A Recycler view using a grid layout that supports auto sizing and showing an empty view when the adapter
* has no items.
* </p>
* <p>
* You can set the column width and column count using styleables:
* </p>
* <ul>
* <li>android:columnWidth=INTEGER</li>
* <li>android:columnCount=INTEGER</li>
* </ul>
*
* Inspired by <a href="http://blog.sqisland.com/2014/12/recyclerview-autofit-grid.html">RecyclerView: Autofit grid</a>
*/
public class RecyclerViewEmptyViewSupport extends RecyclerView {
public final static int AUTO_FIT = -1;
private View emptyView;
private OnItemClickListener onItemClickListener;
private int columnWidth;
private int columnCount = AUTO_FIT;
private GridLayoutManager gridLayoutManager;
private boolean multiColumnSupported;
public interface OnItemClickListener {
void onItemClick(View v, int position);
}
public RecyclerViewEmptyViewSupport(Context context) {
this(context, null);
}
public RecyclerViewEmptyViewSupport(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
@SuppressWarnings("ResourceType")
public RecyclerViewEmptyViewSupport(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setSaveEnabled(true);
if (attrs != null) {
int[] attrsArray = {
android.R.attr.columnWidth, android.R.attr.columnCount
};
TypedArray array = context.obtainStyledAttributes(
attrs, attrsArray);
columnWidth = array.getDimensionPixelSize(0, -1);
columnCount = array.getInteger(1, AUTO_FIT);
array.recycle();
}
gridLayoutManager = new GridLayoutManager(getContext(), 1);
setLayoutManager(gridLayoutManager);
}
@Override
public void setAdapter(final Adapter adapter) {
super.setAdapter(adapter);
if (adapter == null)
return;
adapter.registerAdapterDataObserver(new AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
if (emptyView == null)
return;
if (adapter.getItemCount() == 0) {
emptyView.setVisibility(View.VISIBLE);
setVisibility(View.GONE);
} else {
emptyView.setVisibility(View.GONE);
setVisibility(View.VISIBLE);
}
}
});
}
@Override
public void onViewAdded(final View child) {
super.onViewAdded(child);
child.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onItemClickListener.onItemClick(v, getChildAdapterPosition(child));
}
});
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
int spanCount = Math.max(1, getMeasuredWidth() / columnWidth);
multiColumnSupported = spanCount > 1;
if (columnCount == AUTO_FIT) {
gridLayoutManager.setSpanCount(spanCount);
} else {
gridLayoutManager.setSpanCount(columnCount);
}
}
public boolean isMultiColumnSupported() {
return multiColumnSupported;
}
/**
* Sets the amount of columns.
* @param count amount of columns to use. Use {@link #AUTO_FIT}
* to calculate the amount based on available screen width
* and the specified column width
*/
public void setColumnCount(int count) {
columnCount = count;
invalidate();
}
public int getColumnCount() {
return columnCount;
}
public void setEmptyView(View emptyView) {
this.emptyView = emptyView;
}
public View getEmptyView() {
return emptyView;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}

View File

@ -27,19 +27,11 @@
android:id="@+id/swipe_refresh_layout" android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<GridView <org.xbmc.kore.ui.viewgroups.RecyclerViewEmptyViewSupport
android:id="@+id/list" android:id="@+id/list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="@dimen/small_padding" style="@style/GridLayoutRecyclerView"/>
android:paddingRight="@dimen/small_padding"
android:paddingTop="@dimen/small_padding"
android:paddingBottom="@dimen/default_padding"
android:clipToPadding="false"
android:choiceMode="none"
android:listSelector="?attr/selectableItemBackground"
android:drawSelectorOnTop="true"
style="@style/Widget.GridView"/>
</android.support.v4.widget.SwipeRefreshLayout> </android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout> </FrameLayout>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015 Synced Synapse. All rights reserved.
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.
-->
<!-- TODO: replace gridview with RecyclerViewEmptyViewSupport -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/empty_view"/>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/small_padding"
android:paddingRight="@dimen/small_padding"
android:paddingTop="@dimen/small_padding"
android:paddingBottom="@dimen/default_padding"
android:clipToPadding="false"
android:choiceMode="none"
android:listSelector="?attr/selectableItemBackground"
android:drawSelectorOnTop="true"
style="@style/Widget.GridView"/>
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -17,12 +17,10 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card" android:id="@+id/card"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor"
android:focusable="true" android:focusable="true"
android:clickable="true" android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"> android:foreground="?android:attr/selectableItemBackground">

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"

View File

@ -17,11 +17,9 @@
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
card_view:cardElevation="@dimen/default_card_elevation" style="@style/Widget.CardView">
card_view:cardBackgroundColor="?attr/appCardBackgroundColor">
<RelativeLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"

View File

@ -16,6 +16,8 @@
--> -->
<resources> <resources>
<!-- Default spacing because cardview on lollipop doesn't add padding --> <!-- Default spacing because cardview on lollipop doesn't add padding -->
<dimen name="default_grid_horizontal_spacing">8dp</dimen> <dimen name="default_grid_horizontal_spacing">4dp</dimen>
<dimen name="default_grid_vertical_spacing">8dp</dimen> <dimen name="default_grid_vertical_spacing">4dp</dimen>
<dimen name="default_card_margin">8dp</dimen>
</resources> </resources>

View File

@ -37,6 +37,7 @@
<dimen name="card_corner_radius">2dp</dimen> <dimen name="card_corner_radius">2dp</dimen>
<dimen name="default_card_elevation">2dp</dimen> <dimen name="default_card_elevation">2dp</dimen>
<dimen name="default_card_margin">2dp</dimen>
<dimen name="text_size_small">12sp</dimen> <dimen name="text_size_small">12sp</dimen>
<dimen name="text_size_medium">14sp</dimen> <dimen name="text_size_medium">14sp</dimen>

View File

@ -54,6 +54,21 @@
<item name="android:fastScrollEnabled">true</item> <item name="android:fastScrollEnabled">true</item>
</style> </style>
<style name="GridLayoutRecyclerView">
<item name="android:clipToPadding">false</item>
<item name="android:scrollbars">vertical</item>
<item name="android:paddingBottom">@dimen/default_padding</item>
<item name="android:paddingLeft">@dimen/default_card_margin</item>
<item name="android:columnWidth">@dimen/default_grid_column_width</item>
</style>
<style name="Widget.CardView">
<item name="cardElevation">@dimen/default_card_elevation</item>
<item name="cardBackgroundColor">?attr/appCardBackgroundColor</item>
<item name="android:layout_marginRight">@dimen/default_card_margin</item>
<item name="android:layout_marginTop">@dimen/default_card_margin</item>
</style>
<style name="Widget.ListView"> <style name="Widget.ListView">
<item name="android:fastScrollEnabled">true</item> <item name="android:fastScrollEnabled">true</item>
<item name="android:divider">@null</item> <item name="android:divider">@null</item>