diff options
Diffstat (limited to 'app/src/main/java')
12 files changed, 211 insertions, 64 deletions
diff --git a/app/src/main/java/org/rssin/android/ArticleActivity.java b/app/src/main/java/org/rssin/android/ArticleActivity.java new file mode 100755 index 0000000..2e5460c --- /dev/null +++ b/app/src/main/java/org/rssin/android/ArticleActivity.java @@ -0,0 +1,67 @@ +package org.rssin.android; + +import android.content.Intent; +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.text.Html; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.TextView; + +import org.rssin.rssin.SortedFeedItemContainer; +import org.rssin.rss.FeedItem; +import org.rssin.rssin.R; + +import static org.rssin.neurons.Feedback.*; + +public class ArticleActivity extends ActionBarActivity { + private SortedFeedItemContainer container; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_article); + Intent intent = getIntent(); + Bundle arguments = intent.getExtras(); + container = (SortedFeedItemContainer) arguments.getSerializable("item"); + FeedItem item = container.getFeeditem(); + + TextView title = (TextView) findViewById(R.id.article_title); + title.setText(item.getTitle()); + TextView description = (TextView) findViewById(R.id.article_description); + description.setText(Html.fromHtml(item.getDescription())); + TextView author = (TextView) findViewById(R.id.article_author); + author.setText("Written by: " + item.getAuthor()); + TextView date = (TextView) findViewById(R.id.article_date); + date.setText("Published on: " + item.getPubDate().toString()); + + new Thread(new FeedSorterTrainer(container.getSorter())).start(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_article, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.article_action_dislike) { + container.feedback(Dislike); + return true; + } else if(id == R.id.article_action_like) + { + container.feedback(Like); + return true; + } + + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/org/rssin/android/FeedItemAdapter.java b/app/src/main/java/org/rssin/android/FeedItemAdapter.java index a16f4b5..de1766a 100755 --- a/app/src/main/java/org/rssin/android/FeedItemAdapter.java +++ b/app/src/main/java/org/rssin/android/FeedItemAdapter.java @@ -4,6 +4,7 @@ package org.rssin.android; * @author Jos.
*/
+import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.LayoutInflater;
@@ -11,15 +12,16 @@ import android.view.View; import android.view.ViewGroup;
import android.widget.TextView;
-import org.rssin.rss.FeedItem;
+import org.rssin.neurons.Feedback;
+import org.rssin.rssin.SortedFeedItemContainer;
import org.rssin.rssin.R;
import java.util.List;
class FeedItemAdapter extends RecyclerView.Adapter<FeedItemAdapter.FeedItemHolder> {
- List<FeedItem> feedItems;
+ List<SortedFeedItemContainer> feedItems;
- public FeedItemAdapter(List<FeedItem> objects) {
+ public FeedItemAdapter(List<SortedFeedItemContainer> objects) {
feedItems = objects;
}
@@ -33,9 +35,10 @@ class FeedItemAdapter extends RecyclerView.Adapter<FeedItemAdapter.FeedItemHolde @Override
public void onBindViewHolder(FeedItemHolder holder, int position) {
- FeedItem item = feedItems.get(position);
- holder.title.setText(item.getTitle());
- holder.summary.setText(Html.fromHtml(item.getDescription()));
+ SortedFeedItemContainer item = feedItems.get(position);
+ holder.title.setText(item.getFeeditem().getTitle());
+ holder.summary.setText(Html.fromHtml(item.getFeeditem().getDescription()));
+ holder.item = item;
}
@Override
@@ -43,17 +46,28 @@ class FeedItemAdapter extends RecyclerView.Adapter<FeedItemAdapter.FeedItemHolde return feedItems.size();
}
+
/**
* TextViews holder
*/
static class FeedItemHolder extends RecyclerView.ViewHolder {
TextView title;
TextView summary;
+ SortedFeedItemContainer item;
- public FeedItemHolder(View itemView) {
+ public FeedItemHolder(final View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.feeditem_title);
summary = (TextView) itemView.findViewById(R.id.feeditem_summary);
+ itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(itemView.getContext(), ArticleActivity.class);
+ intent.putExtra("item", item);
+ itemView.getContext().startActivity(intent);
+ item.feedback(Feedback.Like);
+ }
+ });
}
}
}
\ No newline at end of file diff --git a/app/src/main/java/org/rssin/android/FeedSorterTrainer.java b/app/src/main/java/org/rssin/android/FeedSorterTrainer.java new file mode 100755 index 0000000..1289d1a --- /dev/null +++ b/app/src/main/java/org/rssin/android/FeedSorterTrainer.java @@ -0,0 +1,31 @@ +package org.rssin.android;
+
+import android.util.Log;
+
+import org.rssin.neurons.FeedSorter;
+
+import java.util.PriorityQueue;
+
+/**
+ * @author Jos.
+ */
+public class FeedSorterTrainer implements Runnable {
+ private FeedSorter sorter;
+ public FeedSorterTrainer(FeedSorter sorter)
+ {
+ this.sorter = sorter;
+ }
+
+ @Override
+ public void run() {
+ for (int i = 0; i < 50; i++) {
+ Log.d("FeedSorterTrainer", "Training: round " + i);
+ sorter.train();
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/rssin/android/FilterActivity.java b/app/src/main/java/org/rssin/android/FilterActivity.java index 252101a..5003cfb 100755 --- a/app/src/main/java/org/rssin/android/FilterActivity.java +++ b/app/src/main/java/org/rssin/android/FilterActivity.java @@ -1,6 +1,5 @@ package org.rssin.android; -import android.app.Activity; import android.content.Intent; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; @@ -12,7 +11,7 @@ import android.view.MenuItem; import com.android.volley.VolleyError; import org.rssin.listener.FallibleListener; -import org.rssin.rss.FeedItem; +import org.rssin.rssin.SortedFeedItemContainer; import org.rssin.rssin.FeedLoaderAndSorter; import org.rssin.rssin.Filter; import org.rssin.rssin.R; @@ -51,9 +50,9 @@ public class FilterActivity extends ActionBarActivity { setTitle(filter.getTitle()); FeedLoaderAndSorter loaderAndSorter = new FeedLoaderAndSorter(filter); - loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(this), new FallibleListener<List<FeedItem>, VolleyError>() { + loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(this), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() { @Override - public void onReceive(List<FeedItem> data) { + public void onReceive(List<SortedFeedItemContainer> data) { FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data); mRecyclerView.setAdapter(feedItemAdapter); diff --git a/app/src/main/java/org/rssin/android/FiltersList.java b/app/src/main/java/org/rssin/android/FiltersList.java index b555e5e..6b53186 100755 --- a/app/src/main/java/org/rssin/android/FiltersList.java +++ b/app/src/main/java/org/rssin/android/FiltersList.java @@ -12,7 +12,7 @@ import java.util.List; * A list of filters that can be saved using the DefaultStorageProvider * @author Camil Staps */ -class FiltersList { +public class FiltersList { private static FiltersList instance; diff --git a/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java b/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java index 4c23fa9..4c23fa9 100644..100755 --- a/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java +++ b/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java diff --git a/app/src/main/java/org/rssin/android/UnifiedInboxActivity.java b/app/src/main/java/org/rssin/android/UnifiedInboxActivity.java index e38c663..ec8dce7 100755 --- a/app/src/main/java/org/rssin/android/UnifiedInboxActivity.java +++ b/app/src/main/java/org/rssin/android/UnifiedInboxActivity.java @@ -11,8 +11,7 @@ import android.view.MenuItem; import com.android.volley.VolleyError; import org.rssin.listener.FallibleListener; -import org.rssin.rss.FeedItem; -import org.rssin.rssin.FeedLoaderAndSorter; +import org.rssin.rssin.SortedFeedItemContainer; import org.rssin.rssin.Filter; import org.rssin.rssin.R; import org.rssin.rssin.UnifiedFilterLoader; @@ -54,9 +53,9 @@ public class UnifiedInboxActivity extends ActionBarActivity { * results. We could do this for example with {@link org.rssin.listener.RealtimeListener} */ UnifiedFilterLoader loaderAndSorter = new UnifiedFilterLoader(filtersList.getFilters()); - loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(this), new FallibleListener<List<FeedItem>, VolleyError>() { + loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(this), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() { @Override - public void onReceive(List<FeedItem> data) { + public void onReceive(List<SortedFeedItemContainer> data) { FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data); mRecyclerView.setAdapter(feedItemAdapter); mRecyclerView.setHasFixedSize(true); diff --git a/app/src/main/java/org/rssin/neurons/FeedSorter.java b/app/src/main/java/org/rssin/neurons/FeedSorter.java index 6cb369a..4a8fe7e 100755 --- a/app/src/main/java/org/rssin/neurons/FeedSorter.java +++ b/app/src/main/java/org/rssin/neurons/FeedSorter.java @@ -1,6 +1,9 @@ package org.rssin.neurons;
+import android.util.Log;
+
import org.rssin.rss.FeedItem;
+import org.rssin.rssin.SortedFeedItemContainer;
import org.rssin.storage.Storable;
import org.rssin.serialization.SerializationTools;
@@ -9,7 +12,6 @@ import java.util.ArrayList; import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
-import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;
import java.util.Random;
@@ -150,6 +152,8 @@ public class FeedSorter implements Storable { * dislike will move them down.
*/
public void feedback(FeedItem item, Feedback feedback) {
+ Log.d("FeedSorter", "Collected feedback: " + feedback.toString());
+
PredictionInterface prediction = getPrediction(item);
prediction.learn(feedback.toExpectedOutput());
trainingCases.add(new TrainingCase(prediction.getInputs(), feedback));
@@ -163,7 +167,7 @@ public class FeedSorter implements Storable { /**
* Runs an iteration of training, using feedback that was provided previously using FeedSorter.feedback(...).
*/
- public void train() {
+ public synchronized void train() {
Random random = new Random();
for (int i = 0; i < trainingCases.size(); i++) {
TrainingCase t = trainingCases.get(random.nextInt(trainingCases.size()));
@@ -180,26 +184,21 @@ public class FeedSorter implements Storable { /**
* Returns a sorted list of all the items in the List, according to the neural network.
+ * The original list of items is modified.
*
* @param items The list of items.
- * @return A new, sorted, list of items. The parameter items is not modified.
+ * @return A new, sorted, list of items.
*/
- public List<FeedItem> sortItems(List<FeedItem> items) {
+ public List<SortedFeedItemContainer> sortItems(List<SortedFeedItemContainer> items) {
final int SECONDS_IN_DAY = 24 * 60 * 60;
- final List<FeedItem> newItems = new ArrayList<>(items);
- for (FeedItem item : newItems) {
- PredictionInterface prediction = getPrediction(item);
- item.setScore((long) (item.getPubDate().getTime() / 1000 + prediction.getOutput() * SECONDS_IN_DAY));
+ for (SortedFeedItemContainer item : items) {
+ PredictionInterface prediction = getPrediction(item.getFeeditem());
+ item.setScore((long) (item.getFeeditem().getPubDate().getTime() / 1000 + prediction.getOutput() * SECONDS_IN_DAY));
}
- Collections.sort(newItems, new Comparator<FeedItem>() {
- @Override
- public int compare(FeedItem lhs, FeedItem rhs) {
- return (int) Math.signum(rhs.getScore() - lhs.getScore());
- }
- });
+ Collections.sort(items);
- return newItems;
+ return items;
}
}
diff --git a/app/src/main/java/org/rssin/rss/FeedItem.java b/app/src/main/java/org/rssin/rss/FeedItem.java index f7805d8..7128c4c 100755 --- a/app/src/main/java/org/rssin/rss/FeedItem.java +++ b/app/src/main/java/org/rssin/rss/FeedItem.java @@ -1,5 +1,6 @@ package org.rssin.rss; +import java.io.Serializable; import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -7,7 +8,7 @@ import java.util.List; /** * Created by Randy on 19-5-2015. */ -public class FeedItem { +public class FeedItem implements Serializable { private String guid; private Date pubDate; @@ -19,7 +20,6 @@ public class FeedItem { private String enclosure; private String source; 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) @@ -169,17 +169,4 @@ public class FeedItem { && (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 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 7ad0001..3211325 100755 --- a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java +++ b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java @@ -27,9 +27,9 @@ public class FeedLoaderAndSorter { * @param fetcher HTTP Fetcher
* @param listener Listener for when the fetcher finishes
*/
- public void getFilteredFeedItems(Fetcher fetcher, final Listener<List<FeedItem>> listener)
+ public void getFilteredFeedItems(Fetcher fetcher, final Listener<List<SortedFeedItemContainer>> listener)
{
- final List<FeedItem> resultingItems = new ArrayList<>();
+ final List<SortedFeedItemContainer> resultingItems = new ArrayList<>();
final Counter counter = new Counter(filter.getFeeds().size());
final FeedSorter sorter = filter.getFeedSorter();
@@ -39,13 +39,13 @@ public class FeedLoaderAndSorter { @Override
public void onReceive(Object data) {
for (FeedItem item : loader.getFeed().getPosts()) {
- resultingItems.add(item);
+ resultingItems.add(new SortedFeedItemContainer(item, filter));
}
- sorter.sortItems(resultingItems);
+ List<SortedFeedItemContainer> sorted = sorter.sortItems(resultingItems);
if (counter.decr().isZero() || listener.getClass() == RealtimeListener.class) {
- listener.onReceive(resultingItems);
+ listener.onReceive(sorted);
if (counter.decr().isZero() && listener.getClass() == RealtimeListener.class) {
((RealtimeListener) listener).finish();
}
diff --git a/app/src/main/java/org/rssin/rssin/SortedFeedItemContainer.java b/app/src/main/java/org/rssin/rssin/SortedFeedItemContainer.java new file mode 100755 index 0000000..d46cf3b --- /dev/null +++ b/app/src/main/java/org/rssin/rssin/SortedFeedItemContainer.java @@ -0,0 +1,58 @@ +package org.rssin.rssin;
+
+import org.rssin.android.FiltersList;
+import org.rssin.neurons.FeedSorter;
+import org.rssin.neurons.Feedback;
+import org.rssin.rss.FeedItem;
+
+import java.io.Serializable;
+
+/**
+ * @author Jos.
+ */
+public class SortedFeedItemContainer implements Comparable<SortedFeedItemContainer>, Serializable {
+ private FeedItem feeditem;
+ private int filterHashCode;
+ private long score;
+
+ public SortedFeedItemContainer(FeedItem feeditem, Filter filter)
+ {
+ this.feeditem = feeditem;
+ this.filterHashCode = filter.hashCode();
+ this.setScore(-1);
+ }
+
+ public FeedItem getFeeditem() {
+ return feeditem;
+ }
+
+ public FeedSorter getSorter() {
+ FiltersList provider = FiltersList.getInstance();
+ Filter f = provider.getFilterFromHashCode(filterHashCode);
+
+ return f.getFeedSorter();
+ }
+
+ public long getScore() {
+ if(score == -1)
+ {
+ throw new UnsupportedOperationException("score not set");
+ }
+
+ return score;
+ }
+
+ public void feedback(Feedback feedback)
+ {
+ getSorter().feedback(getFeeditem(), feedback);
+ }
+
+ public void setScore(long score) {
+ this.score = score;
+ }
+
+ @Override
+ public int compareTo(SortedFeedItemContainer another) {
+ return (int)(another.getScore() - this.getScore());
+ }
+}
diff --git a/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java b/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java index 9740380..619a152 100755 --- a/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java +++ b/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java @@ -3,11 +3,9 @@ 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;
@@ -28,32 +26,27 @@ public class UnifiedFilterLoader { * @param fetcher HTTP Fetcher
* @param listener Listener for when the fetcher finishes
*/
- public void getFilteredFeedItems(Fetcher fetcher, final Listener<List<FeedItem>> listener) {
+ public void getFilteredFeedItems(Fetcher fetcher, final Listener<List<SortedFeedItemContainer>> 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 HashSet<SortedFeedItemContainer> 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>>() {
+ loaderAndSorter.getFilteredFeedItems(fetcher, new Listener<List<SortedFeedItemContainer>>() {
@Override
- public void onReceive(List<FeedItem> data) {
+ public void onReceive(List<SortedFeedItemContainer> data) {
resultingItems.addAll(data);
if (counter.decr().isZero() || listener.getClass() == RealtimeListener.class) {
- ArrayList<FeedItem> newItems = new ArrayList<FeedItem>(resultingItems);
+ ArrayList<SortedFeedItemContainer> newItems = new ArrayList<SortedFeedItemContainer>(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());
- }
- });
+ Collections.sort(newItems);
listener.onReceive(newItems);
if (counter.decr().isZero() && listener.getClass() == RealtimeListener.class) {
|