WIP: headlines list switched to recycler view
known issues: context menu not working
This commit is contained in:
parent
1ca3a7d681
commit
583578fe8a
@ -32,6 +32,7 @@ dependencies {
|
||||
compile 'com.bogdwellers:pinchtozoom:0.1'
|
||||
compile 'com.github.bumptech.glide:glide:3.8.0'
|
||||
compile 'jp.wasabeef:glide-transformations:2.0.2'
|
||||
compile 'com.android.support:recyclerview-v7:25.3.1'
|
||||
compile 'com.android.support:cardview-v7:25.3.1'
|
||||
compile 'com.android.support:support-v4:25.3.1'
|
||||
compile 'com.android.support:appcompat-v7:25.3.1'
|
||||
|
@ -9,7 +9,6 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@ -18,13 +17,15 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.ActivityOptionsCompat;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.widget.DefaultItemAnimator;
|
||||
import android.support.v7.widget.DividerItemDecoration;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.Html;
|
||||
import android.transition.Fade;
|
||||
import android.transition.Transition;
|
||||
@ -43,12 +44,7 @@ import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AbsListView.OnScrollListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
@ -63,7 +59,6 @@ import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.shamanland.fab.FloatingActionButton;
|
||||
@ -72,6 +67,7 @@ import com.shamanland.fab.ShowHideOnScroll;
|
||||
import org.fox.ttrss.types.Article;
|
||||
import org.fox.ttrss.types.ArticleList;
|
||||
import org.fox.ttrss.types.Feed;
|
||||
import org.fox.ttrss.util.HeaderViewRecyclerAdapter;
|
||||
import org.fox.ttrss.util.HeadlinesRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -85,7 +81,8 @@ import java.util.TimeZone;
|
||||
|
||||
import jp.wasabeef.glide.transformations.CropCircleTransformation;
|
||||
|
||||
public class HeadlinesFragment extends Fragment implements OnItemClickListener, OnScrollListener {
|
||||
public class HeadlinesFragment extends Fragment {
|
||||
|
||||
public enum ArticlesSelection { ALL, NONE, UNREAD }
|
||||
|
||||
public static final int FLAVOR_IMG_MIN_SIZE = 128;
|
||||
@ -100,15 +97,13 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
private Article m_activeArticle;
|
||||
private String m_searchQuery = "";
|
||||
private boolean m_refreshInProgress = false;
|
||||
private boolean m_autoCatchupDisabled = false;
|
||||
private int m_firstId = 0;
|
||||
private boolean m_lazyLoadDisabled = false;
|
||||
|
||||
private SharedPreferences m_prefs;
|
||||
|
||||
private ArticleListAdapter m_adapter;
|
||||
private ArticleList m_articles = new ArticleList(); //Application.getInstance().m_loadedArticles;
|
||||
//private ArticleList m_selectedArticles = new ArticleList();
|
||||
private HeaderViewRecyclerAdapter m_adapter;
|
||||
private ArticleList m_articles = new ArticleList();
|
||||
private ArticleList m_readArticles = new ArticleList();
|
||||
private HeadlinesEventListener m_listener;
|
||||
private OnlineActivity m_activity;
|
||||
@ -116,8 +111,9 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
private int m_maxImageSize = 0;
|
||||
private boolean m_compactLayoutMode = false;
|
||||
private int m_listPreviousVisibleItem;
|
||||
private ListView m_list;
|
||||
//private ImageLoader m_imageLoader = ImageLoader.getInstance();
|
||||
private RecyclerView m_list;
|
||||
private LinearLayoutManager m_layoutManager;
|
||||
|
||||
private View m_listLoadingView;
|
||||
private View m_topChangedView;
|
||||
private View m_amrFooterView;
|
||||
@ -327,7 +323,18 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
}
|
||||
});
|
||||
|
||||
m_list = (ListView) view.findViewById(R.id.headlines_list);
|
||||
m_list = (RecyclerView) view.findViewById(R.id.headlines_list);
|
||||
|
||||
m_layoutManager = new LinearLayoutManager(m_activity.getApplicationContext());
|
||||
m_list.setLayoutManager(m_layoutManager);
|
||||
m_list.setItemAnimator(new DefaultItemAnimator());
|
||||
m_list.addItemDecoration(new DividerItemDecoration(m_list.getContext(), m_layoutManager.getOrientation()));
|
||||
|
||||
ArticleListAdapter adapter = new ArticleListAdapter(getActivity(), R.layout.headlines_row, m_articles);
|
||||
|
||||
m_adapter = new HeaderViewRecyclerAdapter(adapter);
|
||||
|
||||
m_list.setAdapter(m_adapter);
|
||||
|
||||
FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.headlines_fab);
|
||||
|
||||
@ -358,23 +365,91 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
m_amrFooterView = inflater.inflate(R.layout.headlines_footer, container, false);
|
||||
m_amrFooterView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, screenHeight));
|
||||
|
||||
m_list.addFooterView(m_amrFooterView, null, false);
|
||||
m_adapter.addFooterView(m_amrFooterView);
|
||||
}
|
||||
|
||||
if (m_activity.isSmallScreen()) {
|
||||
View layout = inflater.inflate(R.layout.headlines_heading_spacer, m_list, false);
|
||||
m_list.addHeaderView(layout);
|
||||
m_adapter.addHeaderView(layout);
|
||||
|
||||
m_swipeLayout.setProgressViewOffset(false, 0,
|
||||
m_activity.getResources().getDimensionPixelSize(R.dimen.abc_action_bar_default_height_material) +
|
||||
m_activity.getResources().getDimensionPixelSize(R.dimen.abc_action_bar_default_padding_end_material));
|
||||
m_activity.getResources().getDimensionPixelSize(R.dimen.abc_action_bar_default_padding_end_material) + 5);
|
||||
}
|
||||
|
||||
m_adapter = new ArticleListAdapter(getActivity(), R.layout.headlines_row, m_articles);
|
||||
m_list.setAdapter(m_adapter);
|
||||
m_list.setOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
|
||||
super.onScrollStateChanged(recyclerView, newState);
|
||||
|
||||
m_list.setOnItemClickListener(this);
|
||||
m_list.setOnScrollListener(this);
|
||||
if (newState != RecyclerView.SCROLL_STATE_IDLE) {
|
||||
|
||||
try {
|
||||
if (m_mediaPlayer != null && m_mediaPlayer.isPlaying()) {
|
||||
m_mediaPlayer.pause();
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
// i guess it was already released, oh well
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE && m_prefs.getBoolean("headlines_mark_read_scroll", false)) {
|
||||
if (!m_readArticles.isEmpty()) {
|
||||
m_activity.toggleArticlesUnread(m_readArticles);
|
||||
m_activity.refresh(false);
|
||||
m_readArticles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||
super.onScrolled(recyclerView, dx, dy);
|
||||
|
||||
int firstVisibleItem = m_layoutManager.findFirstVisibleItemPosition();
|
||||
int lastVisibleItem = m_layoutManager.findLastVisibleItemPosition();
|
||||
|
||||
//Log.d(TAG, "onScrolled: FVI=" + firstVisibleItem + " LVI=" + lastVisibleItem);
|
||||
|
||||
if (m_prefs.getBoolean("headlines_mark_read_scroll", false) && firstVisibleItem > m_adapter.getHeaderCount()) {
|
||||
|
||||
if (firstVisibleItem <= m_articles.size()) {
|
||||
|
||||
Article a = (Article) m_articles.get(firstVisibleItem - m_adapter.getHeaderCount() - 1);
|
||||
|
||||
if (a != null && a.unread) {
|
||||
Log.d(TAG, "title=" + a.title);
|
||||
|
||||
a.unread = false;
|
||||
m_readArticles.add(a);
|
||||
m_feed.unread--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_activity.isTablet()) {
|
||||
if (m_adapter.getItemCount() > 0) {
|
||||
if (firstVisibleItem > m_listPreviousVisibleItem) {
|
||||
m_activity.getSupportActionBar().hide();
|
||||
} else if (firstVisibleItem < m_listPreviousVisibleItem) {
|
||||
m_activity.getSupportActionBar().show();
|
||||
}
|
||||
} else {
|
||||
m_activity.getSupportActionBar().show();
|
||||
}
|
||||
|
||||
m_listPreviousVisibleItem = firstVisibleItem;
|
||||
}
|
||||
|
||||
if (!m_refreshInProgress && !m_lazyLoadDisabled && lastVisibleItem >= m_articles.size() - 5) {
|
||||
refresh(true);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
if (!enableSwipeToDismiss) registerForContextMenu(m_list);
|
||||
|
||||
@ -412,38 +487,15 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
m_listener = (HeadlinesEventListener) activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> av, View view, int position, long id) {
|
||||
ListView list = (ListView)av;
|
||||
|
||||
Log.d(TAG, "onItemClick=" + position);
|
||||
|
||||
if (list != null) {
|
||||
Article article = (Article)list.getItemAtPosition(position);
|
||||
|
||||
// could be footer or w/e
|
||||
if (article != null && article.id >= 0) {
|
||||
m_listener.onArticleSelected(article);
|
||||
|
||||
// only set active article when it makes sense (in DetailActivity)
|
||||
if (getActivity() instanceof DetailActivity) {
|
||||
m_activeArticle = article;
|
||||
}
|
||||
|
||||
m_adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh(boolean append) {
|
||||
refresh(append, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "serial" })
|
||||
public void refresh(boolean append, boolean userInitiated) {
|
||||
m_list.removeFooterView(m_listLoadingView);
|
||||
m_list.removeFooterView(m_topChangedView);
|
||||
m_list.removeFooterView(m_amrFooterView);
|
||||
public void refresh(final boolean append, boolean userInitiated) {
|
||||
m_adapter.removeFooterView(m_listLoadingView);
|
||||
m_adapter.removeFooterView(m_topChangedView);
|
||||
m_adapter.removeFooterView(m_amrFooterView);
|
||||
|
||||
if (!append) m_lazyLoadDisabled = false;
|
||||
|
||||
@ -452,19 +504,6 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
|
||||
if (m_swipeLayout != null) m_swipeLayout.setRefreshing(true);
|
||||
|
||||
// new stuff may appear on top, scroll back to show it
|
||||
if (!append) {
|
||||
if (getView() != null) {
|
||||
Log.d(TAG, "scroll hack");
|
||||
m_autoCatchupDisabled = true;
|
||||
m_list.setSelection(0);
|
||||
m_autoCatchupDisabled = false;
|
||||
m_articles.clear();
|
||||
m_adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
final boolean fappend = append;
|
||||
final String sessionId = m_activity.getSessionId();
|
||||
final boolean isCat = m_feed.is_cat;
|
||||
|
||||
@ -482,10 +521,9 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
|
||||
if (m_swipeLayout != null) m_swipeLayout.setRefreshing(false);
|
||||
|
||||
//m_listLoadingView.setVisibility(View.GONE);
|
||||
m_list.removeFooterView(m_listLoadingView);
|
||||
m_list.removeFooterView(m_topChangedView);
|
||||
m_list.removeFooterView(m_amrFooterView);
|
||||
m_adapter.removeFooterView(m_listLoadingView);
|
||||
m_adapter.removeFooterView(m_topChangedView);
|
||||
m_adapter.removeFooterView(m_amrFooterView);
|
||||
|
||||
if (result != null) {
|
||||
m_refreshInProgress = false;
|
||||
@ -497,7 +535,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
if (m_firstIdChanged) {
|
||||
m_lazyLoadDisabled = true;
|
||||
|
||||
m_list.addFooterView(m_topChangedView, null, false);
|
||||
m_adapter.addFooterView(m_topChangedView);
|
||||
}
|
||||
|
||||
if (m_amountLoaded < HEADLINES_REQUEST_SIZE) {
|
||||
@ -507,16 +545,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
HeadlinesFragment.this.m_firstId = m_firstId;
|
||||
|
||||
m_adapter.notifyDataSetChanged();
|
||||
m_listener.onHeadlinesLoaded(fappend);
|
||||
|
||||
// not sure why but listview sometimes gets positioned while ignoring the header so
|
||||
// top headline content becomes partially obscured by the toolbar on phones
|
||||
// (not reproducible on avd)
|
||||
if (!fappend) {
|
||||
m_list.smoothScrollToPosition(0);
|
||||
}
|
||||
|
||||
//m_listLoadingView.setVisibility(m_amountLoaded == HEADLINES_REQUEST_SIZE ? View.VISIBLE : View.GONE);
|
||||
m_listener.onHeadlinesLoaded(append);
|
||||
|
||||
} else {
|
||||
if (m_lastError == ApiCommon.ApiError.LOGIN_FAILED) {
|
||||
@ -531,7 +560,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
}
|
||||
}
|
||||
|
||||
if (m_amrFooterView != null) m_list.addFooterView(m_amrFooterView, null, false);
|
||||
if (m_amrFooterView != null) m_adapter.addFooterView(m_amrFooterView);
|
||||
}
|
||||
};
|
||||
|
||||
@ -562,12 +591,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
}
|
||||
|
||||
if (skip > 0) {
|
||||
m_list.addFooterView(m_listLoadingView, null, false);
|
||||
//m_listLoadingView.setVisibility(View.VISIBLE);
|
||||
m_adapter.addFooterView(m_listLoadingView);
|
||||
}
|
||||
|
||||
} else {
|
||||
//m_activity.setLoadingStatus(R.string.blank, true);
|
||||
}
|
||||
|
||||
final int fskip = skip;
|
||||
@ -638,7 +663,10 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
out.putBoolean("lazyLoadDisabled", m_lazyLoadDisabled);
|
||||
}
|
||||
|
||||
static class HeadlineViewHolder {
|
||||
static class HeadlineViewHolder extends RecyclerView.ViewHolder {
|
||||
public View view;
|
||||
public Article article;
|
||||
|
||||
public TextView titleView;
|
||||
public TextView feedTitleView;
|
||||
public ImageView markedView;
|
||||
@ -659,11 +687,39 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
public View topChangedMessage;
|
||||
public View flavorImageOverflow;
|
||||
public SurfaceView flavorVideoView;
|
||||
public int position;
|
||||
//public int position;
|
||||
public boolean flavorImageEmbedded;
|
||||
|
||||
public HeadlineViewHolder(View v) {
|
||||
super(v);
|
||||
|
||||
view = v;
|
||||
|
||||
titleView = (TextView)v.findViewById(R.id.title);
|
||||
|
||||
feedTitleView = (TextView)v.findViewById(R.id.feed_title);
|
||||
markedView = (ImageView)v.findViewById(R.id.marked);
|
||||
publishedView = (ImageView)v.findViewById(R.id.published);
|
||||
excerptView = (TextView)v.findViewById(R.id.excerpt);
|
||||
flavorImageView = (ImageView) v.findViewById(R.id.flavor_image);
|
||||
flavorVideoKindView = (ImageView) v.findViewById(R.id.flavor_video_kind);
|
||||
authorView = (TextView)v.findViewById(R.id.author);
|
||||
dateView = (TextView) v.findViewById(R.id.date);
|
||||
selectionBoxView = (CheckBox) v.findViewById(R.id.selected);
|
||||
menuButtonView = (ImageView) v.findViewById(R.id.article_menu_button);
|
||||
flavorImageHolder = (ViewGroup) v.findViewById(R.id.flavorImageHolder);
|
||||
flavorImageLoadingBar = (ProgressBar) v.findViewById(R.id.flavorImageLoadingBar);
|
||||
headlineFooter = v.findViewById(R.id.headline_footer);
|
||||
textImage = (ImageView) v.findViewById(R.id.text_image);
|
||||
textChecked = (ImageView) v.findViewById(R.id.text_checked);
|
||||
headlineHeader = v.findViewById(R.id.headline_header);
|
||||
topChangedMessage = v.findViewById(R.id.headlines_row_top_changed);
|
||||
flavorImageOverflow = v.findViewById(R.id.flavor_image_overflow);
|
||||
flavorVideoView = (SurfaceView) v.findViewById(R.id.flavor_video);
|
||||
}
|
||||
}
|
||||
|
||||
private class ArticleListAdapter extends ArrayAdapter<Article> {
|
||||
private class ArticleListAdapter extends RecyclerView.Adapter<HeadlineViewHolder> {
|
||||
private ArrayList<Article> items;
|
||||
|
||||
public static final int VIEW_NORMAL = 0;
|
||||
@ -678,14 +734,14 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
|
||||
private ColorGenerator m_colorGenerator = ColorGenerator.DEFAULT;
|
||||
private TextDrawable.IBuilder m_drawableBuilder = TextDrawable.builder().round();
|
||||
//private final DisplayImageOptions displayImageOptions;
|
||||
|
||||
boolean showFlavorImage;
|
||||
private int m_minimumHeightToEmbed;
|
||||
boolean m_youtubeInstalled;
|
||||
private int m_screenHeight;
|
||||
|
||||
public ArticleListAdapter(Context context, int textViewResourceId, ArrayList<Article> items) {
|
||||
super(context, textViewResourceId, items);
|
||||
super();
|
||||
this.items = items;
|
||||
|
||||
Display display = m_activity.getWindowManager().getDefaultDisplay();
|
||||
@ -702,13 +758,6 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
theme.resolveAttribute(R.attr.headlineTitleHighScoreUnreadTextColor, tv, true);
|
||||
titleHighScoreUnreadColor = tv.data;
|
||||
|
||||
/*displayImageOptions = new DisplayImageOptions.Builder()
|
||||
.cacheInMemory(true)
|
||||
.resetViewBeforeLoading(true)
|
||||
.cacheOnDisk(true)
|
||||
.displayer(new FadeInBitmapDisplayer(500))
|
||||
.build();*/
|
||||
|
||||
List<ApplicationInfo> packages = m_activity.getPackageManager().getInstalledApplications(0);
|
||||
for (ApplicationInfo pi : packages) {
|
||||
if (pi.packageName.equals("com.google.android.youtube")) {
|
||||
@ -718,93 +767,12 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
}
|
||||
}
|
||||
|
||||
public int getViewTypeCount() {
|
||||
return VIEW_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
Article a = items.get(position);
|
||||
public HeadlineViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
|
||||
if (m_activeArticle != null && a.id == m_activeArticle.id && a.unread) {
|
||||
return VIEW_SELECTED_UNREAD;
|
||||
} else if (m_activeArticle != null && a.id == m_activeArticle.id) {
|
||||
return VIEW_SELECTED;
|
||||
} else if (a.unread) {
|
||||
return VIEW_UNREAD;
|
||||
} else {
|
||||
return VIEW_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTextCheckedState(final HeadlineViewHolder holder, final Article article, final int position) {
|
||||
String tmp = article.title.length() > 0 ? article.title.substring(0, 1).toUpperCase() : "?";
|
||||
|
||||
if (article.selected) {
|
||||
holder.textImage.setImageDrawable(m_drawableBuilder.build(" ", 0xff616161));
|
||||
//holder.textImage.setTag(null);
|
||||
|
||||
holder.textChecked.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
final Drawable textDrawable = m_drawableBuilder.build(tmp, m_colorGenerator.getColor(article.title));
|
||||
|
||||
holder.textImage.setImageDrawable(textDrawable);
|
||||
//holder.textImage.setTag(null);
|
||||
|
||||
//holder.textChecked.setVisibility(View.GONE);
|
||||
|
||||
if (!showFlavorImage || article.flavorImage == null) {
|
||||
holder.textImage.setImageDrawable(textDrawable);
|
||||
//holder.textImage.setTag(null);
|
||||
} else {
|
||||
|
||||
//final GlideDrawableImageViewTarget glideImage = new GlideDrawableImageViewTarget(holder.textImage);
|
||||
|
||||
Glide.with(HeadlinesFragment.this)
|
||||
.load(article.flavorImageUri)
|
||||
.placeholder(textDrawable)
|
||||
.bitmapTransform(new CropCircleTransformation(getActivity()))
|
||||
.dontAnimate()
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.skipMemoryCache(false)
|
||||
.listener(new RequestListener<String, GlideDrawable>() {
|
||||
@Override
|
||||
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
|
||||
|
||||
if (resource.getIntrinsicWidth() < THUMB_IMG_MIN_SIZE || resource.getIntrinsicHeight() < THUMB_IMG_MIN_SIZE) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})
|
||||
.into(holder.textImage);
|
||||
}
|
||||
|
||||
holder.textChecked.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int position, final View convertView, ViewGroup parent) {
|
||||
|
||||
View v = convertView;
|
||||
|
||||
final Article article = items.get(position);
|
||||
final HeadlineViewHolder holder;
|
||||
|
||||
int headlineFontSize = Integer.parseInt(m_prefs.getString("headlines_font_size_sp", "13"));
|
||||
int headlineSmallFontSize = Math.max(10, Math.min(18, headlineFontSize - 2));
|
||||
|
||||
if (v == null) {
|
||||
int layoutId = m_compactLayoutMode ? R.layout.headlines_row_compact : R.layout.headlines_row;
|
||||
|
||||
switch (getItemViewType(position)) {
|
||||
switch (viewType) {
|
||||
case VIEW_UNREAD:
|
||||
layoutId = m_compactLayoutMode ? R.layout.headlines_row_unread_compact : R.layout.headlines_row_unread;
|
||||
break;
|
||||
@ -816,43 +784,43 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
break;
|
||||
}
|
||||
|
||||
LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
v = vi.inflate(layoutId, null);
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
|
||||
|
||||
holder = new HeadlineViewHolder();
|
||||
holder.titleView = (TextView)v.findViewById(R.id.title);
|
||||
|
||||
holder.feedTitleView = (TextView)v.findViewById(R.id.feed_title);
|
||||
holder.markedView = (ImageView)v.findViewById(R.id.marked);
|
||||
holder.publishedView = (ImageView)v.findViewById(R.id.published);
|
||||
holder.excerptView = (TextView)v.findViewById(R.id.excerpt);
|
||||
holder.flavorImageView = (ImageView) v.findViewById(R.id.flavor_image);
|
||||
holder.flavorVideoKindView = (ImageView) v.findViewById(R.id.flavor_video_kind);
|
||||
holder.authorView = (TextView)v.findViewById(R.id.author);
|
||||
holder.dateView = (TextView) v.findViewById(R.id.date);
|
||||
holder.selectionBoxView = (CheckBox) v.findViewById(R.id.selected);
|
||||
holder.menuButtonView = (ImageView) v.findViewById(R.id.article_menu_button);
|
||||
holder.flavorImageHolder = (ViewGroup) v.findViewById(R.id.flavorImageHolder);
|
||||
holder.flavorImageLoadingBar = (ProgressBar) v.findViewById(R.id.flavorImageLoadingBar);
|
||||
holder.headlineFooter = v.findViewById(R.id.headline_footer);
|
||||
holder.textImage = (ImageView) v.findViewById(R.id.text_image);
|
||||
holder.textChecked = (ImageView) v.findViewById(R.id.text_checked);
|
||||
holder.headlineHeader = v.findViewById(R.id.headline_header);
|
||||
holder.topChangedMessage = v.findViewById(R.id.headlines_row_top_changed);
|
||||
holder.flavorImageOverflow = v.findViewById(R.id.flavor_image_overflow);
|
||||
holder.flavorVideoView = (SurfaceView) v.findViewById(R.id.flavor_video);
|
||||
|
||||
v.setTag(holder);
|
||||
|
||||
// http://code.google.com/p/android/issues/detail?id=3414
|
||||
((ViewGroup)v).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
|
||||
} else {
|
||||
holder = (HeadlineViewHolder) v.getTag();
|
||||
return new HeadlineViewHolder(v);
|
||||
}
|
||||
|
||||
//Log.d(TAG, "getView: " + position + ":" + article.title);
|
||||
@Override
|
||||
public void onBindViewHolder(final HeadlineViewHolder holder, final int position) {
|
||||
holder.article = items.get(position);
|
||||
|
||||
holder.position = position;
|
||||
int headlineFontSize = Integer.parseInt(m_prefs.getString("headlines_font_size_sp", "13"));
|
||||
int headlineSmallFontSize = Math.max(10, Math.min(18, headlineFontSize - 2));
|
||||
|
||||
final Article article = holder.article;
|
||||
|
||||
//holder.position = position;
|
||||
|
||||
holder.view.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
m_activity.openContextMenu(v);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
holder.view.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
m_listener.onArticleSelected(article);
|
||||
|
||||
// only set active article when it makes sense (in DetailActivity)
|
||||
if (getActivity() instanceof DetailActivity) {
|
||||
m_activeArticle = article;
|
||||
}
|
||||
|
||||
m_adapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
|
||||
// block footer clicks to make button/selection clicking easier
|
||||
if (holder.headlineFooter != null) {
|
||||
@ -1319,8 +1287,6 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
}
|
||||
|
||||
if (holder.menuButtonView != null) {
|
||||
//if (m_activity.isDarkTheme())
|
||||
// ib.setImageResource(R.drawable.ic_mailbox_collapsed_holo_dark);
|
||||
|
||||
holder.menuButtonView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
@ -1345,7 +1311,73 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
});
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
Article a = items.get(position);
|
||||
|
||||
if (m_activeArticle != null && a.id == m_activeArticle.id && a.unread) {
|
||||
return VIEW_SELECTED_UNREAD;
|
||||
} else if (m_activeArticle != null && a.id == m_activeArticle.id) {
|
||||
return VIEW_SELECTED;
|
||||
} else if (a.unread) {
|
||||
return VIEW_UNREAD;
|
||||
} else {
|
||||
return VIEW_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
private void updateTextCheckedState(final HeadlineViewHolder holder, final Article article, final int position) {
|
||||
String tmp = article.title.length() > 0 ? article.title.substring(0, 1).toUpperCase() : "?";
|
||||
|
||||
if (article.selected) {
|
||||
holder.textImage.setImageDrawable(m_drawableBuilder.build(" ", 0xff616161));
|
||||
//holder.textImage.setTag(null);
|
||||
|
||||
holder.textChecked.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
final Drawable textDrawable = m_drawableBuilder.build(tmp, m_colorGenerator.getColor(article.title));
|
||||
|
||||
holder.textImage.setImageDrawable(textDrawable);
|
||||
|
||||
if (!showFlavorImage || article.flavorImage == null) {
|
||||
holder.textImage.setImageDrawable(textDrawable);
|
||||
|
||||
} else {
|
||||
Glide.with(HeadlinesFragment.this)
|
||||
.load(article.flavorImageUri)
|
||||
.placeholder(textDrawable)
|
||||
.bitmapTransform(new CropCircleTransformation(getActivity()))
|
||||
.dontAnimate()
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.skipMemoryCache(false)
|
||||
.listener(new RequestListener<String, GlideDrawable>() {
|
||||
@Override
|
||||
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
|
||||
|
||||
if (resource.getIntrinsicWidth() < THUMB_IMG_MIN_SIZE || resource.getIntrinsicHeight() < THUMB_IMG_MIN_SIZE) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})
|
||||
.into(holder.textImage);
|
||||
}
|
||||
|
||||
holder.textChecked.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void openGalleryForType(Article article, HeadlineViewHolder holder, View transitionView) {
|
||||
@ -1430,14 +1462,6 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
return px;
|
||||
}
|
||||
|
||||
private void repositionFlavorVideo(View view, HeadlineViewHolder holder) {
|
||||
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) view.getLayoutParams();
|
||||
|
||||
lp.addRule(RelativeLayout.BELOW, R.id.headline_header);
|
||||
|
||||
view.setLayoutParams(lp);
|
||||
}
|
||||
|
||||
private void maybeRepositionFlavorImage(View view, GlideDrawable resource, HeadlineViewHolder holder, boolean forceDown) {
|
||||
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) view.getLayoutParams();
|
||||
|
||||
@ -1523,14 +1547,9 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
|
||||
m_adapter.notifyDataSetChanged();
|
||||
|
||||
ListView list = (ListView)getView().findViewById(R.id.headlines_list);
|
||||
|
||||
if (list != null) {
|
||||
if (m_list != null) {
|
||||
int position = getArticlePositionById(article.id);
|
||||
|
||||
if (position != -1) {
|
||||
list.smoothScrollToPosition(position);
|
||||
}
|
||||
m_list.smoothScrollToPosition(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1553,15 +1572,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
}
|
||||
|
||||
public Article getArticleAtPosition(int position) {
|
||||
try {
|
||||
return (Article) m_list.getItemAtPosition(position);
|
||||
} catch (ClassCastException e) {
|
||||
return null;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return null;
|
||||
} catch (NullPointerException e) {
|
||||
return null;
|
||||
}
|
||||
return m_articles.get(position);
|
||||
}
|
||||
|
||||
public Article getArticleById(int id) {
|
||||
@ -1580,74 +1591,14 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
|
||||
if (m_prefs.getBoolean("headlines_mark_read_scroll", false) && firstVisibleItem > (m_activity.isSmallScreen() ? 1 : 0) && !m_autoCatchupDisabled) {
|
||||
Article a = (Article) view.getItemAtPosition(firstVisibleItem - 1);
|
||||
|
||||
if (a != null && a.unread) {
|
||||
Log.d(TAG, "title=" + a.title);
|
||||
|
||||
a.unread = false;
|
||||
m_readArticles.add(a);
|
||||
m_feed.unread--;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_activity.isTablet()) {
|
||||
if (m_adapter.getCount() > 0) {
|
||||
if (firstVisibleItem > m_listPreviousVisibleItem) {
|
||||
m_activity.getSupportActionBar().hide();
|
||||
} else if (firstVisibleItem < m_listPreviousVisibleItem) {
|
||||
m_activity.getSupportActionBar().show();
|
||||
}
|
||||
} else {
|
||||
m_activity.getSupportActionBar().show();
|
||||
}
|
||||
|
||||
m_listPreviousVisibleItem = firstVisibleItem;
|
||||
}
|
||||
|
||||
if (!m_refreshInProgress && !m_lazyLoadDisabled && firstVisibleItem + visibleItemCount == m_articles.size()) {
|
||||
refresh(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
||||
if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING || scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
|
||||
|
||||
/*if (m_activeSurface != null) {
|
||||
m_activeSurface.setVisibility(View.GONE);
|
||||
}*/
|
||||
|
||||
try {
|
||||
if (m_mediaPlayer != null && m_mediaPlayer.isPlaying()) {
|
||||
m_mediaPlayer.pause();
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
// i guess it was already released, oh well
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (scrollState == SCROLL_STATE_IDLE && m_prefs.getBoolean("headlines_mark_read_scroll", false)) {
|
||||
if (!m_readArticles.isEmpty()) {
|
||||
m_activity.toggleArticlesUnread(m_readArticles);
|
||||
m_activity.refresh(false);
|
||||
m_readArticles.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Article getActiveArticle() {
|
||||
return m_activeArticle;
|
||||
}
|
||||
|
||||
public int getArticlePositionById(int id) {
|
||||
for (Article a : m_adapter.items) {
|
||||
if (a.id == id) {
|
||||
return m_adapter.getPosition(a) + m_list.getHeaderViewsCount();
|
||||
for (int i = 0; i < m_articles.size(); i++) {
|
||||
if (m_articles.get(i).id == id) {
|
||||
return i + m_adapter.getHeaderCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,214 @@
|
||||
package org.fox.ttrss.util;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 darnmason
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* RecyclerView adapter designed to wrap an existing adapter allowing the addition of
|
||||
* header views and footer views.
|
||||
* </p>
|
||||
* <p>
|
||||
* I implemented it to aid with the transition from ListView to RecyclerView where the ListView's
|
||||
* addHeaderView and addFooterView methods were used. Using this class you may initialize your
|
||||
* header views in the Fragment/Activity and add them to the adapter in the same way you used to
|
||||
* add them to a ListView.
|
||||
* </p>
|
||||
* <p>
|
||||
* I also required to be able to swap out multiple adapters with different content, therefore
|
||||
* setAdapter may be called multiple times.
|
||||
* </p>
|
||||
* Created by darnmason on 07/11/2014.
|
||||
*/
|
||||
public class HeaderViewRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private static final int HEADERS_START = Integer.MIN_VALUE;
|
||||
private static final int FOOTERS_START = Integer.MIN_VALUE + 10;
|
||||
private static final int ITEMS_START = Integer.MIN_VALUE + 20;
|
||||
private static final int ADAPTER_MAX_TYPES = 100;
|
||||
|
||||
private RecyclerView.Adapter mWrappedAdapter;
|
||||
private List<View> mHeaderViews, mFooterViews;
|
||||
private Map<Class, Integer> mItemTypesOffset;
|
||||
|
||||
/**
|
||||
* Construct a new header view recycler adapter
|
||||
* @param adapter The underlying adapter to wrap
|
||||
*/
|
||||
public HeaderViewRecyclerAdapter(RecyclerView.Adapter adapter) {
|
||||
mHeaderViews = new ArrayList<View>();
|
||||
mFooterViews = new ArrayList<View>();
|
||||
mItemTypesOffset = new HashMap<Class, Integer>();
|
||||
setWrappedAdapter(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the underlying adapter, notifying RecyclerView of changes
|
||||
* @param adapter The new adapter to wrap
|
||||
*/
|
||||
public void setAdapter(RecyclerView.Adapter adapter) {
|
||||
if(mWrappedAdapter != null && mWrappedAdapter.getItemCount() > 0) {
|
||||
notifyItemRangeRemoved(getHeaderCount(), mWrappedAdapter.getItemCount());
|
||||
}
|
||||
setWrappedAdapter(adapter);
|
||||
notifyItemRangeInserted(getHeaderCount(), mWrappedAdapter.getItemCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
int hCount = getHeaderCount();
|
||||
if (position < hCount) return HEADERS_START + position;
|
||||
else {
|
||||
int itemCount = mWrappedAdapter.getItemCount();
|
||||
if (position < hCount + itemCount) {
|
||||
return getAdapterTypeOffset() + mWrappedAdapter.getItemViewType(position - hCount);
|
||||
}
|
||||
else return FOOTERS_START + position - hCount - itemCount;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
|
||||
if (viewType < HEADERS_START + getHeaderCount())
|
||||
return new StaticViewHolder(mHeaderViews.get(viewType - HEADERS_START));
|
||||
else if (viewType < FOOTERS_START + getFooterCount())
|
||||
return new StaticViewHolder(mFooterViews.get(viewType - FOOTERS_START));
|
||||
else {
|
||||
return mWrappedAdapter.onCreateViewHolder(viewGroup, viewType - getAdapterTypeOffset());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
||||
int hCount = getHeaderCount();
|
||||
if (position >= hCount && position < hCount + mWrappedAdapter.getItemCount())
|
||||
mWrappedAdapter.onBindViewHolder(viewHolder, position - hCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a static view to appear at the start of the RecyclerView. Headers are displayed in the
|
||||
* order they were added.
|
||||
* @param view The header view to add
|
||||
*/
|
||||
public void addHeaderView(View view) {
|
||||
mHeaderViews.add(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a static view to appear at the end of the RecyclerView. Footers are displayed in the
|
||||
* order they were added.
|
||||
* @param view The footer view to add
|
||||
*/
|
||||
public void addFooterView(View view) {
|
||||
mFooterViews.add(view);
|
||||
}
|
||||
|
||||
public void removeFooterView(View view) {
|
||||
mFooterViews.remove(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return getHeaderCount() + getFooterCount() + getWrappedItemCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The item count in the underlying adapter
|
||||
*/
|
||||
public int getWrappedItemCount() {
|
||||
return mWrappedAdapter.getItemCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of header views added
|
||||
*/
|
||||
public int getHeaderCount() {
|
||||
return mHeaderViews.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of footer views added
|
||||
*/
|
||||
public int getFooterCount() {
|
||||
return mFooterViews.size();
|
||||
}
|
||||
|
||||
private void setWrappedAdapter(RecyclerView.Adapter adapter) {
|
||||
if (mWrappedAdapter != null) mWrappedAdapter.unregisterAdapterDataObserver(mDataObserver);
|
||||
mWrappedAdapter = adapter;
|
||||
Class adapterClass = mWrappedAdapter.getClass();
|
||||
if(!mItemTypesOffset.containsKey(adapterClass)) putAdapterTypeOffset(adapterClass);
|
||||
mWrappedAdapter.registerAdapterDataObserver(mDataObserver);
|
||||
}
|
||||
|
||||
private void putAdapterTypeOffset(Class adapterClass) {
|
||||
mItemTypesOffset.put(adapterClass, ITEMS_START + mItemTypesOffset.size() * ADAPTER_MAX_TYPES);
|
||||
}
|
||||
|
||||
private int getAdapterTypeOffset() {
|
||||
return mItemTypesOffset.get(mWrappedAdapter.getClass());
|
||||
}
|
||||
|
||||
private RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeChanged(int positionStart, int itemCount) {
|
||||
super.onItemRangeChanged(positionStart, itemCount);
|
||||
notifyItemRangeChanged(positionStart + getHeaderCount(), itemCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeInserted(int positionStart, int itemCount) {
|
||||
super.onItemRangeInserted(positionStart, itemCount);
|
||||
notifyItemRangeInserted(positionStart + getHeaderCount(), itemCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeRemoved(int positionStart, int itemCount) {
|
||||
super.onItemRangeRemoved(positionStart, itemCount);
|
||||
notifyItemRangeRemoved(positionStart + getHeaderCount(), itemCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
|
||||
super.onItemRangeMoved(fromPosition, toPosition, itemCount);
|
||||
int hCount = getHeaderCount();
|
||||
// TODO: No notifyItemRangeMoved method?
|
||||
notifyItemRangeChanged(fromPosition + hCount, toPosition + hCount + itemCount);
|
||||
}
|
||||
};
|
||||
|
||||
private static class StaticViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public StaticViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
}
|
||||
}
|
@ -11,24 +11,13 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<ListView
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/headlines_list"
|
||||
android:drawSelectorOnTop="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
<!-- <TextView
|
||||
android:id="@+id/no_headlines"
|
||||
android:clickable="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/no_headlines"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:visibility="invisible" >
|
||||
</TextView> -->
|
||||
|
||||
<com.shamanland.fab.FloatingActionButton
|
||||
android:id="@+id/headlines_fab"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -3,7 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/headlines_row"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<TableLayout
|
||||
|
@ -3,7 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/headlines_row"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?headlineUnreadBackground"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user