aboutsummaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/org/rssin/android/FilterActivity.java95
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/FeedSorter.java13
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/Feedback.java3
-rwxr-xr-x[-rw-r--r--]app/src/main/java/org/rssin/rss/FeedItem.java64
-rwxr-xr-xapp/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java14
-rwxr-xr-xapp/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java84
-rw-r--r--app/src/main/res/layout/activity_filter.xml20
-rw-r--r--app/src/main/res/layout/item_feeditem.xml38
8 files changed, 266 insertions, 65 deletions
diff --git a/app/src/main/java/org/rssin/android/FilterActivity.java b/app/src/main/java/org/rssin/android/FilterActivity.java
index b1be925..6c827d1 100644
--- a/app/src/main/java/org/rssin/android/FilterActivity.java
+++ b/app/src/main/java/org/rssin/android/FilterActivity.java
@@ -5,6 +5,8 @@ import android.content.Context;
import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -31,10 +33,17 @@ public class FilterActivity extends ActionBarActivity {
private FiltersList filtersList;
private Filter filter;
+ private RecyclerView mRecyclerView;
+ private RecyclerView.Adapter mAdapter;
+ private RecyclerView.LayoutManager mLayoutManager;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_filter);
+ mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
+ mLayoutManager = new LinearLayoutManager(this);
+ mRecyclerView.setLayoutManager(mLayoutManager);
try {
filtersList = FiltersList.getInstance(this);
@@ -52,13 +61,14 @@ public class FilterActivity extends ActionBarActivity {
setTitle(filter.getTitle());
final Activity activity = this;
- final ListView itemsListView = (ListView) findViewById(R.id.filter_items_list);
FeedLoaderAndSorter loaderAndSorter = new FeedLoaderAndSorter(filter);
loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(this), new FallibleListener<List<FeedItem>, VolleyError>() {
@Override
public void onReceive(List<FeedItem> data) {
- FeedItemAdapter feedItemAdapter = new FeedItemAdapter(activity, R.layout.item_feeditem, data);
- itemsListView.setAdapter(feedItemAdapter);
+
+ FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data);
+ mRecyclerView.setAdapter(feedItemAdapter);
+ mRecyclerView.setHasFixedSize(true);
}
@Override
@@ -101,49 +111,72 @@ public class FilterActivity extends ActionBarActivity {
/**
* Custom ArrayAdapter to display Keywords
*/
- private static class FeedItemAdapter extends ArrayAdapter<FeedItem> {
- Context context;
- int layoutResourceId;
+ private static class FeedItemAdapter extends RecyclerView.Adapter<FeedItemAdapter.KeywordHolder> {
List<FeedItem> feedItems;
- public FeedItemAdapter(Context context, int resource, List<FeedItem> objects) {
- super(context, resource, objects);
- this.context = context;
- layoutResourceId = resource;
+ public FeedItemAdapter(List<FeedItem> objects) {
feedItems = objects;
}
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View row = convertView;
- KeywordHolder holder = null;
-
- if (row == null) {
- LayoutInflater inflater = ((Activity) context).getLayoutInflater();
- row = inflater.inflate(layoutResourceId, parent, false);
+// @Override
+// public View getView(int position, View convertView, ViewGroup parent) {
+// View row = convertView;
+// KeywordHolder holder = null;
+//
+// if (row == null) {
+// LayoutInflater inflater = ((Activity) context).getLayoutInflater();
+// row = inflater.inflate(layoutResourceId, parent, false);
+//
+// holder = new KeywordHolder();
+// holder.title = (TextView) row.findViewById(R.id.feeditem_title);
+// holder.summary = (TextView) row.findViewById(R.id.feeditem_summary);
+//
+// row.setTag(holder);
+// } else {
+// holder = (KeywordHolder) row.getTag();
+// }
+//
+// FeedItem feedItem = feedItems.get(position);
+// holder.title.setText(feedItem.getTitle());
+// holder.summary.setText(Html.fromHtml(feedItem.getDescription()));
+//
+// return row;
+// }
- holder = new KeywordHolder();
- holder.title = (TextView) row.findViewById(R.id.feeditem_title);
- holder.summary = (TextView) row.findViewById(R.id.feeditem_summary);
-
- row.setTag(holder);
- } else {
- holder = (KeywordHolder) row.getTag();
- }
+ @Override
+ public KeywordHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View itemView = LayoutInflater.
+ from(parent.getContext()).
+ inflate(R.layout.item_feeditem, parent, false);
+ return new KeywordHolder(itemView);
+ }
- FeedItem feedItem = feedItems.get(position);
- holder.title.setText(feedItem.getTitle());
- holder.summary.setText(Html.fromHtml(feedItem.getDescription()));
+ @Override
+ public void onBindViewHolder(KeywordHolder holder, int position) {
+ FeedItem item = feedItems.get(position);
+ holder.title.setText(item.getTitle());
+ holder.summary.setText(item.getDescription());
+ }
- return row;
+ @Override
+ public int getItemCount() {
+ return feedItems.size();
}
/**
* TextViews holder
*/
- private static class KeywordHolder {
+ static class KeywordHolder extends RecyclerView.ViewHolder {
TextView title;
TextView summary;
+
+ public KeywordHolder(View itemView) {
+ super(itemView);
+ title = (TextView) itemView.findViewById(R.id.feeditem_title);
+ summary = (TextView) itemView.findViewById(R.id.feeditem_summary);
+ }
}
+
+
}
}
diff --git a/app/src/main/java/org/rssin/neurons/FeedSorter.java b/app/src/main/java/org/rssin/neurons/FeedSorter.java
index 910057f..fe1e998 100755
--- a/app/src/main/java/org/rssin/neurons/FeedSorter.java
+++ b/app/src/main/java/org/rssin/neurons/FeedSorter.java
@@ -33,7 +33,7 @@ public class FeedSorter implements Storable {
private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
stream.writeObject(nn);
- stream.writeObject(trainingCases);
+ SerializationTools.writeList(trainingCases, stream);
SerializationTools.writeArray(isNthMonthInput, stream);
SerializationTools.writeArray(isNthWeekDayInput, stream);
stream.writeInt(isMorning);
@@ -48,7 +48,7 @@ public class FeedSorter implements Storable {
private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
nn = (MultiNeuralNetwork) stream.readObject();
- trainingCases = (List<TrainingCase>) stream.readObject();
+ trainingCases = SerializationTools.readList(stream);
isNthMonthInput = SerializationTools.readArrayInt(stream);
isNthWeekDayInput = SerializationTools.readArrayInt(stream);
isMorning = stream.readInt();
@@ -183,22 +183,17 @@ public class FeedSorter implements Storable {
*/
public List<FeedItem> sortItems(List<FeedItem> items) {
final int SECONDS_IN_DAY = 24 * 60 * 60;
-
final List<FeedItem> newItems = new ArrayList<>(items);
- final Hashtable<FeedItem, Long> predictions = new Hashtable<>();
for (FeedItem item : newItems) {
PredictionInterface prediction = getPrediction(item);
- predictions.put(item, (long) (prediction.getOutput() * SECONDS_IN_DAY));
+ item.setScore((long) (item.getPubDate().getTime() / 1000 + prediction.getOutput() * SECONDS_IN_DAY));
}
Collections.sort(newItems, new Comparator<FeedItem>() {
@Override
public int compare(FeedItem lhs, FeedItem rhs) {
- long lhsScore = lhs.getPubDate().getTime() / 1000 + predictions.get(lhs);
- long rhsScore = rhs.getPubDate().getTime() / 1000 + predictions.get(rhs);
-
- return (int) Math.signum(rhsScore - lhsScore);
+ return (int) Math.signum(rhs.getScore() - lhs.getScore());
}
});
diff --git a/app/src/main/java/org/rssin/neurons/Feedback.java b/app/src/main/java/org/rssin/neurons/Feedback.java
index fe59b1b..59d3246 100755
--- a/app/src/main/java/org/rssin/neurons/Feedback.java
+++ b/app/src/main/java/org/rssin/neurons/Feedback.java
@@ -2,13 +2,14 @@ package org.rssin.neurons;
/**
* @author Jos.
+ * Feedback for the Neural Network.
*/
public enum Feedback {
Like(1.0d), Dislike(-1.0d);
private final double expectedOutput;
- private Feedback(double expectedOutput) {
+ Feedback(double expectedOutput) {
this.expectedOutput = expectedOutput;
}
diff --git a/app/src/main/java/org/rssin/rss/FeedItem.java b/app/src/main/java/org/rssin/rss/FeedItem.java
index bb074cd..f7805d8 100644..100755
--- a/app/src/main/java/org/rssin/rss/FeedItem.java
+++ b/app/src/main/java/org/rssin/rss/FeedItem.java
@@ -15,11 +15,11 @@ public class FeedItem {
private String description;
private String link;
private String author;
- private List<String> category = new LinkedList<>();
private String comments;
private String enclosure;
private String source;
- private boolean isRead;
+ private List<String> category = new LinkedList<>();
+ private transient long score = -1;
public FeedItem(String guid, Date pubDate, String title, String description, String link,
String author, List<String> category, String comments, String enclosure, String source)
@@ -123,11 +123,63 @@ public class FeedItem {
return title + "\n" + description + " - " + author;
}
- public boolean isRead() {
- return isRead;
+ @Override
+ public int hashCode() {
+ int hash = 17;
+
+ if(guid != null)
+ {
+ hash = hash * 23 + guid.hashCode();
+ }
+
+ if(link != null)
+ {
+ hash = hash * 23 + link.hashCode();
+ }
+
+ if(title != null)
+ {
+ hash = hash * 23 + title.hashCode();
+ }
+
+ if(pubDate != null)
+ {
+ hash = hash * 23 + pubDate.hashCode();
+ }
+
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof FeedItem))
+ return false;
+
+ if (obj == this)
+ return true;
+
+ FeedItem other = (FeedItem) obj;
+ return (guid == null && other.guid == null) || (guid != null && guid.equals(other.guid))
+ && (pubDate == null && other.pubDate == null) || (pubDate != null && pubDate.equals(other.pubDate))
+ && (title == null && other.title == null) || (title != null && title.equals(other.title))
+ && (description == null && other.description == null) || (description != null && description.equals(other.description))
+ && (link == null && other.link == null) || (link != null && link.equals(other.link))
+ && (author == null && other.author == null) || (author != null && author.equals(other.author))
+ && (comments == null && other.comments == null) || (comments != null && comments.equals(other.comments))
+ && (enclosure == null && other.enclosure == null) || (enclosure != null && enclosure.equals(other.enclosure))
+ && (source == null && other.source == null) || (source != null && source.equals(other.source));
+ }
+
+ public long getScore() {
+ if(score == -1)
+ {
+ throw new UnsupportedOperationException("score not set");
+ }
+
+ return score;
}
- public void setIsRead(boolean isRead) {
- this.isRead = isRead;
+ public void setScore(long score) {
+ this.score = score;
}
}
diff --git a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java
index 2ec3cfd..e1fbbab 100755
--- a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java
+++ b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java
@@ -85,10 +85,22 @@ public class FeedLoaderAndSorter {
{
for(Keyword keyword : filter.getKeywords())
{
- if(contains(item.getTitle(), keyword.getKeyword()))
+ String word = keyword.getKeyword();
+ if(contains(item.getTitle(), word)
+ || contains(item.getAuthor(), word))
{
return true;
}
+
+
+
+ for(String category : item.getCategory())
+ {
+ if(contains(category, word))
+ {
+ return true;
+ }
+ }
}
return filter.getKeywords().size() == 0;
diff --git a/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java b/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java
new file mode 100755
index 0000000..9740380
--- /dev/null
+++ b/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java
@@ -0,0 +1,84 @@
+package org.rssin.rssin;
+
+import org.rssin.http.Fetcher;
+import org.rssin.listener.Listener;
+import org.rssin.listener.RealtimeListener;
+import org.rssin.rss.FeedItem;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * @author Jos.
+ * This class merges the FeedItems from multiple Filters together into one list of FeedItems.
+ */
+public class UnifiedFilterLoader {
+
+ private List<Filter> filters;
+ public UnifiedFilterLoader(List<Filter> filters)
+ {
+ this.filters = filters;
+ }
+
+ /**
+ * Loads the feed(s), filters it, sorts it, and returns the result.
+ * @param fetcher HTTP Fetcher
+ * @param listener Listener for when the fetcher finishes
+ */
+ public void getFilteredFeedItems(Fetcher fetcher, final Listener<List<FeedItem>> listener) {
+ // HashSet to make sure that there are no duplicates when merging multiple filters, since different filters
+ // may contain the same feed.
+ final HashSet<FeedItem> resultingItems = new HashSet<>();
+ final Counter counter = new Counter(filters.size());
+
+ for (Filter filter : filters) {
+ // Load the sorted FeedItems from the filters, and combine them.
+ FeedLoaderAndSorter loaderAndSorter = new FeedLoaderAndSorter(filter);
+ loaderAndSorter.getFilteredFeedItems(fetcher, new Listener<List<FeedItem>>() {
+ @Override
+ public void onReceive(List<FeedItem> data) {
+ resultingItems.addAll(data);
+
+ if (counter.decr().isZero() || listener.getClass() == RealtimeListener.class) {
+ ArrayList<FeedItem> newItems = new ArrayList<FeedItem>(resultingItems);
+
+ // Do another sort to make sure the items are still in the correct order.
+ // this uses the score set by the FeedSorter class, which is called
+ // in the Filter class. The Unified inbox does not have a separate network.
+ Collections.sort(newItems, new Comparator<FeedItem>() {
+ @Override
+ public int compare(FeedItem lhs, FeedItem rhs) {
+ return (int) Math.signum(rhs.getScore() - lhs.getScore());
+ }
+ });
+
+ listener.onReceive(newItems);
+ if (counter.decr().isZero() && listener.getClass() == RealtimeListener.class) {
+ ((RealtimeListener) listener).finish();
+ }
+ }
+ }
+ });
+ }
+ }
+
+ private static class Counter {
+ int count;
+
+ Counter (int initial) {
+ count = initial;
+ }
+
+ public Counter decr() {
+ count--;
+ return this;
+ }
+
+ public boolean isZero() {
+ return count == 0;
+ }
+ }
+}
diff --git a/app/src/main/res/layout/activity_filter.xml b/app/src/main/res/layout/activity_filter.xml
index b144d08..19b7fad 100644
--- a/app/src/main/res/layout/activity_filter.xml
+++ b/app/src/main/res/layout/activity_filter.xml
@@ -1,13 +1,15 @@
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="org.rssin.android.FilterActivity">
- <ListView
- android:id="@+id/filter_items_list"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+xmlns:tools="http://schemas.android.com/tools"
+android:layout_width="match_parent"
+android:layout_height="match_parent"
+tools:context="org.rssin.android.FilterActivity">
+ <!-- A RecyclerView with some commonly used attributes -->
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/my_recycler_view"
+ android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
-</RelativeLayout>
+ </LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_feeditem.xml b/app/src/main/res/layout/item_feeditem.xml
index 9f4c553..0b3c944 100644
--- a/app/src/main/res/layout/item_feeditem.xml
+++ b/app/src/main/res/layout/item_feeditem.xml
@@ -1,19 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:padding="10dp">
+ android:padding="15dp">
- <TextView android:id="@+id/feeditem_title"
- android:layout_width="fill_parent"
+ <android.support.v7.widget.CardView
+ android:id="@+id/filter_items_list"
+ android:layout_gravity="center"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textSize="@dimen/font_size_normal"/>
+ card_view:cardElevation="4dp"
+ card_view:cardCornerRadius="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="8dp">
+
+ <TextView android:id="@+id/feeditem_title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Lorem Ipsum Dolor Sit Amet"
+ android:textSize="@dimen/font_size_huge"/>
+ <TextView android:id="@+id/feeditem_summary"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eu pulvinar sapien, vel hendrerit lectus. Donec et sem lorem. Phasellus pharetra ornare ligula, sit amet volutpat nunc. Aenean posuere neque et leo gravida faucibus. Nunc ut neque sagittis, hendrerit tortor sit amet, interdum nisl. Quisque nibh elit, varius sed eros at, euismod commodo orci. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis interdum, sem porttitor feugiat fringilla, nunc ex blandit lorem, in ultrices dolor sapien et lorem. Vestibulum sit amet feugiat enim, eu luctus turpis. "
+ android:textSize="@dimen/font_size_small"/>
+
+ </LinearLayout>
+
+
+ </android.support.v7.widget.CardView>
- <TextView android:id="@+id/feeditem_summary"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:textSize="@dimen/font_size_small"/>
</LinearLayout> \ No newline at end of file