diff --git a/org.fox.ttrss/build.gradle b/org.fox.ttrss/build.gradle
index d5c23ef9..a8c99c78 100644
--- a/org.fox.ttrss/build.gradle
+++ b/org.fox.ttrss/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 19
+ compileSdkVersion 21
buildToolsVersion "20.0.0"
defaultConfig {
applicationId "org.fox.ttrss"
- minSdkVersion 8
+ minSdkVersion 9
targetSdkVersion 19
}
@@ -24,12 +24,14 @@ android {
dependencies {
compile project(':taskerlocaleapi')
+ compile 'com.android.support:cardview-v7:21.0.0'
+ compile 'com.android.support:recyclerview-v7:21.0.0'
compile 'com.jeremyfeinstein.slidingmenu:library:1.3@aar'
compile 'com.readystatesoftware.systembartint:systembartint:1.0.3'
compile 'com.viewpagerindicator:library:2.4.1'
- compile 'com.android.support:support-v4:19.1.0'
+ compile 'com.android.support:support-v4:19.0.0'
+ compile 'com.android.support:appcompat-v7:19.0.0'
compile 'com.google.code.gson:gson:1.7.1'
- compile 'com.android.support:appcompat-v7:19.1.0'
compile files('libs/dashclock-api-r1.1.jar')
compile files('libs/jsoup-1.6.1.jar')
compile files('libs/universal-image-loader-1.9.3.jar')
diff --git a/org.fox.ttrss/org.fox.ttrss.iml b/org.fox.ttrss/org.fox.ttrss.iml
index ea2bf186..7f3fbd73 100644
--- a/org.fox.ttrss/org.fox.ttrss.iml
+++ b/org.fox.ttrss/org.fox.ttrss.iml
@@ -78,13 +78,16 @@
-
+
+
+
+
+
+
-
-
diff --git a/org.fox.ttrss/src/main/AndroidManifest.xml b/org.fox.ttrss/src/main/AndroidManifest.xml
index 939326af..dfa5f247 100644
--- a/org.fox.ttrss/src/main/AndroidManifest.xml
+++ b/org.fox.ttrss/src/main/AndroidManifest.xml
@@ -37,6 +37,8 @@
android:name=".FeedsActivity"
android:label="@string/app_name"
android:uiOptions="splitActionBarWhenNarrow" >
+
@@ -45,6 +47,8 @@
android:name=".HeadlinesActivity"
android:label="@string/app_name"
android:uiOptions="splitActionBarWhenNarrow" >
+
@@ -68,11 +72,17 @@
android:name=".offline.OfflineFeedsActivity"
android:label="@string/app_name"
android:uiOptions="splitActionBarWhenNarrow" >
+
+
+
+
)m_articles);
-
- /* if (!m_activity.isCompatMode()) {
- AnimationSet set = new AnimationSet(true);
-
- Animation animation = new AlphaAnimation(0.0f, 1.0f);
- animation.setDuration(500);
- set.addAnimation(animation);
-
- animation = new TranslateAnimation(
- Animation.RELATIVE_TO_SELF, 50.0f,Animation.RELATIVE_TO_SELF, 0.0f,
- Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f
- );
- animation.setDuration(1000);
- set.addAnimation(animation);
-
- LayoutAnimationController controller = new LayoutAnimationController(set, 0.5f);
-
- list.setLayoutAnimation(controller);
- } */
-
+ final RecyclerView list = (RecyclerView)view.findViewById(R.id.headlines);
+
+ m_adapter = new ArticleListAdapter(m_articles);
+
+ list.setLayoutManager(new LinearLayoutManager(getActivity()));
list.setAdapter(m_adapter);
- list.setOnItemClickListener(this);
- list.setOnScrollListener(this);
- //list.setEmptyView(view.findViewById(R.id.no_headlines));
registerForContextMenu(list);
-
+
+ list.setOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+
+ if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE && m_prefs.getBoolean("headlines_mark_read_scroll", false)) {
+ Log.d(TAG, "scroll ended!");
+
+ 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);
+
+ LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
+
+ int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
+ int visibleItemCount = layoutManager.findLastCompletelyVisibleItemPosition() - layoutManager.findFirstVisibleItemPosition() + 1;
+
+ Log.d(TAG, "fvI= " + firstVisibleItem + " vIC=" + visibleItemCount);
+
+ if (!m_refreshInProgress && m_articles.findById(-1) != null && firstVisibleItem + visibleItemCount == m_articles.size()) {
+ refresh(true);
+ }
+
+ if (m_prefs.getBoolean("headlines_mark_read_scroll", false) && firstVisibleItem > 0 && !m_autoCatchupDisabled) {
+ Article a = m_articles.get(firstVisibleItem - 1);
+
+ if (a != null && a.unread) {
+ a.unread = false;
+ m_readArticles.add(a);
+ m_feed.unread--;
+ }
+ }
+
+ }
+ });
+
//m_activity.m_pullToRefreshAttacher.addRefreshableView(list, this);
//if (m_activity.isSmallScreen())
@@ -385,7 +413,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
m_listener = (HeadlinesEventListener) activity;
}
- @Override
+ /* @Override
public void onItemClick(AdapterView> av, View view, int position, long id) {
ListView list = (ListView)av;
@@ -404,7 +432,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
m_adapter.notifyDataSetChanged();
}
}
- }
+ } */
public void refresh(boolean append) {
refresh(append, false);
@@ -426,11 +454,11 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
if (!append) {
if (getView() != null) {
Log.d(TAG, "scroll hack");
- ListView list = (ListView)getView().findViewById(R.id.headlines);
+ RecyclerView list = (RecyclerView) getView().findViewById(R.id.headlines);
m_autoCatchupDisabled = true;
- list.setSelection(0);
+ //list.setSelection(0);
m_autoCatchupDisabled = false;
- list.setEmptyView(null);
+ //list.setEmptyView(null);
m_adapter.clear();
m_adapter.notifyDataSetChanged();
}
@@ -450,13 +478,13 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
protected void onPostExecute(JsonElement result) {
if (isDetached()) return;
- if (getView() != null) {
+ /* if (getView() != null) {
ListView list = (ListView)getView().findViewById(R.id.headlines);
if (list != null) {
list.setEmptyView(getView().findViewById(R.id.no_headlines));
}
- }
+ } */
m_activity.setProgressBarVisibility(false);
@@ -651,23 +679,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
}
} */
- static class HeadlineViewHolder {
- public TextView titleView;
- public TextView feedTitleView;
- public ImageView markedView;
- public ImageView publishedView;
- public TextView excerptView;
- public ImageView flavorImageView;
- public TextView authorView;
- public TextView dateView;
- public CheckBox selectionBoxView;
- public ImageView menuButtonView;
- public ViewGroup flavorImageHolder;
-
- }
-
- private class ArticleListAdapter extends ArrayAdapter {
- private ArrayList items;
+ private class ArticleListAdapter extends RecyclerArrayAdapter {
+ //private ArrayList items;
public static final int VIEW_NORMAL = 0;
public static final int VIEW_UNREAD = 1;
@@ -680,7 +693,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
private final Integer[] origTitleColors = new Integer[VIEW_COUNT];
private final int titleHighScoreUnreadColor;
- public ArticleListAdapter(Context context, int textViewResourceId, ArrayList items) {
+ /* public ArticleListAdapter(Context context, int textViewResourceId, ArrayList items) {
super(context, textViewResourceId, items);
this.items = items;
@@ -688,15 +701,106 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
TypedValue tv = new TypedValue();
theme.resolveAttribute(R.attr.headlineTitleHighScoreUnreadTextColor, tv, true);
titleHighScoreUnreadColor = tv.data;
- }
-
+ } */
+
+ public class HeadlineViewHolder extends RecyclerView.ViewHolder {
+ public TextView titleView;
+ public TextView feedTitleView;
+ public ImageView markedView;
+ public ImageView publishedView;
+ public TextView excerptView;
+ public ImageView flavorImageView;
+ public TextView authorView;
+ public TextView dateView;
+ public CheckBox selectionBoxView;
+ public ImageView menuButtonView;
+ public ViewGroup flavorImageHolder;
+ public View headlineView;
+
+ public HeadlineViewHolder(View v) {
+ super(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);
+ 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);
+ headlineView = v;
+ }
+ }
+
+
+ // Create new views (invoked by the layout manager)
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
+ int viewType) {
+ /* // create a new view
+ View v = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.my_text_view, parent, false);
+ // set the view's size, margins, paddings and layout parameters
+ ...
+ ViewHolder vh = new ViewHolder(v);
+ return vh; */
+
+ int layoutId = R.layout.headlines_row;
+
+ switch (viewType) {
+ case VIEW_LOADMORE:
+ layoutId = R.layout.headlines_row_loadmore;
+ break;
+ case VIEW_UNREAD:
+ layoutId = R.layout.headlines_row_unread;
+ break;
+ case VIEW_SELECTED:
+ layoutId = R.layout.headlines_row_selected;
+ break;
+ case VIEW_SELECTED_UNREAD:
+ layoutId = R.layout.headlines_row_selected_unread;
+ break;
+ }
+
+ View v = LayoutInflater.from(parent.getContext())
+ .inflate(layoutId, parent, false);
+
+ ((ViewGroup)v).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+
+ HeadlineViewHolder vh = new HeadlineViewHolder(v);
+
+ return vh;
+ }
+
+ /* @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ HeadlineViewHolder avh = (HeadlineViewHolder) holder;
+
+ // - get element from your dataset at this position
+ // - replace the contents of the view with that element
+ //holder.mTextView.setText(mDataset[position]);
+
+ } */
+
+ public ArticleListAdapter(ArrayList items) {
+ super(items);
+
+ Theme theme = getActivity().getTheme();
+ TypedValue tv = new TypedValue();
+ theme.resolveAttribute(R.attr.headlineTitleHighScoreUnreadTextColor, tv, true);
+ titleHighScoreUnreadColor = tv.data;
+ }
+
public int getViewTypeCount() {
return VIEW_COUNT;
}
@Override
public int getItemViewType(int position) {
- Article a = items.get(position);
+ Article a = m_items.get(position);
if (a.id == -1) {
return VIEW_LOADMORE;
@@ -711,61 +815,32 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
}
}
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
-
- final Article article = items.get(position);
- HeadlineViewHolder holder;
-
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder h, final int position) {
+ HeadlineViewHolder holder = (HeadlineViewHolder) h;
+ final Article article = m_items.get(position);
+
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 = R.layout.headlines_row;
-
- switch (getItemViewType(position)) {
- case VIEW_LOADMORE:
- layoutId = R.layout.headlines_row_loadmore;
- break;
- case VIEW_UNREAD:
- layoutId = R.layout.headlines_row_unread;
- break;
- case VIEW_SELECTED:
- layoutId = R.layout.headlines_row_selected;
- break;
- case VIEW_SELECTED_UNREAD:
- layoutId = R.layout.headlines_row_selected_unread;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
- holder = new HeadlineViewHolder();
- holder.titleView = (TextView)v.findViewById(R.id.title);
+ holder.headlineView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (article.id >= 0) {
+ m_listener.onArticleSelected(article);
- 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.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);
-
- 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();
- }
-
- if (holder.titleView != null) {
+ // only set active article when it makes sense (in HeadlinesActivity)
+ if (getActivity().findViewById(R.id.article_fragment) != null) {
+ m_activeArticle = article;
+ }
+
+ m_adapter.notifyDataSetChanged();
+ }
+ }
+ });
+
+ if (holder.titleView != null) {
holder.titleView.setText(Html.fromHtml(article.title));
if (m_prefs.getBoolean("enable_condensed_fonts", false)) {
@@ -982,8 +1057,6 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
}
});
}
-
- return v;
}
private void adjustTitleTextView(int score, TextView tv, int position) {
@@ -1067,7 +1140,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
return tmp;
}
- @Override
+ /* @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (!m_refreshInProgress && m_articles.findById(-1) != null && firstVisibleItem + visibleItemCount == m_articles.size()) {
refresh(true);
@@ -1093,7 +1166,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
m_readArticles.clear();
}
}
- }
+ } */
public Article getActiveArticle() {
return m_activeArticle;
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java
index c1adef52..10cc1c9a 100644
--- a/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java
+++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java
@@ -152,11 +152,11 @@ public class OnlineActivity extends CommonActivity {
setAppTheme(m_prefs);
- super.onCreate(savedInstanceState);
+ if (canUseProgress()) {
+ requestWindowFeature(Window.FEATURE_PROGRESS);
+ }
- if (canUseProgress()) {
- requestWindowFeature(Window.FEATURE_PROGRESS);
- }
+ super.onCreate(savedInstanceState);
//requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/RecyclerArrayAdapter.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/RecyclerArrayAdapter.java
new file mode 100644
index 00000000..2f6fdd82
--- /dev/null
+++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/RecyclerArrayAdapter.java
@@ -0,0 +1,94 @@
+package org.fox.ttrss.util;
+
+import android.support.v7.widget.RecyclerView;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Created by pascalwelsch on 04.07.14.
+ */
+public abstract class RecyclerArrayAdapter
+ extends RecyclerView.Adapter {
+
+ protected List m_items;
+
+ public RecyclerArrayAdapter(final List objects) {
+ m_items = objects;
+ }
+
+ /**
+ * Adds the specified object at the end of the array.
+ *
+ * @param object The object to add at the end of the array.
+ */
+ public void add(final T object) {
+ m_items.add(object);
+ notifyItemInserted(getItemCount() - 1);
+ }
+
+ /**
+ * Remove all elements from the list.
+ */
+ public void clear() {
+ final int size = getItemCount();
+ m_items.clear();
+ notifyItemRangeRemoved(0, size);
+ }
+
+ @Override
+ public int getItemCount() {
+ return m_items.size();
+ }
+
+ public T getItem(final int position) {
+ return m_items.get(position);
+ }
+
+ public long getItemId(final int position) {
+ return position;
+ }
+
+ /**
+ * Returns the position of the specified item in the array.
+ *
+ * @param item The item to retrieve the position of.
+ * @return The position of the specified item.
+ */
+ public int getPosition(final T item) {
+ return m_items.indexOf(item);
+ }
+
+ /**
+ * Inserts the specified object at the specified index in the array.
+ *
+ * @param object The object to insert into the array.
+ * @param index The index at which the object must be inserted.
+ */
+ public void insert(final T object, int index) {
+ m_items.add(index, object);
+ notifyItemInserted(index);
+
+ }
+
+ /**
+ * Removes the specified object from the array.
+ *
+ * @param object The object to remove.
+ */
+ public void remove(T object) {
+ final int position = getPosition(object);
+ m_items.remove(object);
+ notifyItemRemoved(position);
+ }
+
+ /**
+ * Sorts the content of this adapter using the specified comparator.
+ *
+ * @param comparator The comparator used to sort the objects contained in this adapter.
+ */
+ public void sort(Comparator super T> comparator) {
+ Collections.sort(m_items, comparator);
+ notifyItemRangeChanged(0, getItemCount());
+ }
+}
\ No newline at end of file
diff --git a/org.fox.ttrss/src/main/res/layout/headlines_fragment.xml b/org.fox.ttrss/src/main/res/layout/headlines_fragment.xml
index 63f7f856..16e25520 100644
--- a/org.fox.ttrss/src/main/res/layout/headlines_fragment.xml
+++ b/org.fox.ttrss/src/main/res/layout/headlines_fragment.xml
@@ -9,15 +9,15 @@
android:layout_width="match_parent"
android:layout_height="match_parent" >
-
-
+