diff options
21 files changed, 170 insertions, 691 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c0a9eed..1403185 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,14 +14,6 @@ android:label="@string/title_activity_settings" > </activity> <activity - android:name="org.rssin.android.FiltersActivity" - android:label="@string/title_activity_filters" - android:parentActivityName="org.rssin.android.HomeScreenActivity" > - <meta-data - android:name="android.support.PARENT_ACTIVITY" - android:value="org.rssin.android.HomeScreenActivity" /> - </activity> - <activity android:name="org.rssin.android.FilterSettingsActivity" android:label="@string/title_activity_filter_settings" > <meta-data @@ -29,14 +21,6 @@ android:value="org.rssin.android.HomeScreenActivity" /> </activity> <activity - android:name="org.rssin.android.FilterActivity" - android:label="@string/title_activity_filter" - android:parentActivityName="org.rssin.android.HomeScreenActivity" > - <meta-data - android:name="android.support.PARENT_ACTIVITY" - android:value="org.rssin.android.HomeScreenActivity" /> - </activity> - <activity android:name="org.rssin.android.FeedsActivity" android:label="@string/title_activity_feeds" android:parentActivityName="org.rssin.android.HomeScreenActivity" > diff --git a/app/src/main/java/org/rssin/android/ArticleActivity.java b/app/src/main/java/org/rssin/android/ArticleActivity.java index a6bf4d8..165ac54 100755 --- a/app/src/main/java/org/rssin/android/ArticleActivity.java +++ b/app/src/main/java/org/rssin/android/ArticleActivity.java @@ -49,7 +49,7 @@ public class ArticleActivity extends ActionBarActivity { date.setText(R.string.article_published_on_unknown); } - new Thread(new FeedSorterTrainer(container.getSorter())).start(); + new Thread(new FeedSorterTrainer(FeedSorterProvider.getInstance(this))).start(); } catch (NullPointerException e) { Frontend.error(this, R.string.error_load_article, e); finish(); @@ -73,12 +73,12 @@ public class ArticleActivity extends ActionBarActivity { //noinspection SimplifiableIfStatement if (id == R.id.article_action_dislike) { Toast.makeText(this, "Feedback saved.", Toast.LENGTH_SHORT).show(); - container.feedback(Dislike); + container.feedback(this, Dislike); return true; } else if(id == R.id.article_action_like) { Toast.makeText(this, "Feedback saved.", Toast.LENGTH_SHORT).show(); - container.feedback(Like); + container.feedback(this, Like); return true; } diff --git a/app/src/main/java/org/rssin/android/FeedItemAdapter.java b/app/src/main/java/org/rssin/android/FeedItemAdapter.java index 7a606ef..6b092c4 100755 --- a/app/src/main/java/org/rssin/android/FeedItemAdapter.java +++ b/app/src/main/java/org/rssin/android/FeedItemAdapter.java @@ -48,10 +48,9 @@ class FeedItemAdapter extends RecyclerView.Adapter<FeedItemAdapter.FeedItemHolde public void onBindViewHolder(FeedItemHolder holder, int position) {
SortedFeedItemContainer item = feedItems.get(position);
holder.title.setText(item.getFeeditem().getTitle());
- //holder.summary.setText(Html.fromHtml(item.getFeeditem().getDescription()));
holder.summary.setText(sapInterface.getSummary(item.getFeeditem()).getText());
- +
holder.item = item;
}
@@ -81,7 +80,7 @@ class FeedItemAdapter extends RecyclerView.Adapter<FeedItemAdapter.FeedItemHolde Intent intent = new Intent(itemView.getContext(), ArticleActivity.class);
intent.putExtra("item", item);
itemView.getContext().startActivity(intent);
- item.feedback(Feedback.Like);
+ item.feedback(itemView.getContext(), Feedback.Like);
}
});
}
diff --git a/app/src/main/java/org/rssin/android/FeedSorterProvider.java b/app/src/main/java/org/rssin/android/FeedSorterProvider.java new file mode 100755 index 0000000..3e8dec5 --- /dev/null +++ b/app/src/main/java/org/rssin/android/FeedSorterProvider.java @@ -0,0 +1,81 @@ +package org.rssin.android;
+
+import android.content.Context;
+import android.util.Log;
+
+import org.rssin.neurons.FeedSorter;
+import org.rssin.storage.StorageProvider;
+
+import java.io.IOException;
+
+/**
+ * @author Jos.
+ */
+public class FeedSorterProvider {
+ private static FeedSorterProvider instance;
+ private FeedSorter sorter = null;
+ private final String storageKey = "FeedSorter";
+ private InternalStorageProvider storageProvider;
+
+ private FeedSorterProvider(Context context)
+ {
+ storageProvider = InternalStorageProvider.getInstance(context);
+ }
+
+ public static FeedSorterProvider getInstance()
+ {
+ return instance;
+ }
+
+ public static FeedSorterProvider getInstance(Context context)
+ {
+ if(instance == null)
+ {
+ instance = new FeedSorterProvider(context);
+ }
+
+ return instance;
+ }
+
+ public FeedSorter getFeedSorter()
+ {
+ if(sorter == null)
+ {
+ try {
+ sorter = (FeedSorter) storageProvider.fetch(storageKey, FeedSorter.class);
+ } catch (IOException e) {
+ sorter = new FeedSorter();
+ this.save();
+ }
+ }
+
+ return sorter;
+ }
+
+ public synchronized void save()
+ {
+ FeedSorterStorer storer = new FeedSorterStorer(storageKey, storageProvider, sorter);
+ new Thread(storer).start();
+ }
+
+ private class FeedSorterStorer implements Runnable {
+ private final Object storageKey;
+ private final StorageProvider storageProvider;
+ private final FeedSorter feedSorter;
+
+ public FeedSorterStorer(Object storageKey, StorageProvider storageProvider, FeedSorter feedSorter) {
+ this.storageKey = storageKey;
+ this.storageProvider = storageProvider;
+ this.feedSorter = feedSorter;
+ }
+
+ @Override
+ public void run() {
+ try {
+ storageProvider.store(storageKey, feedSorter);
+ } catch (Exception e) {
+ Log.e("Filter", "Failed to store FeedSorter", e);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/rssin/android/FeedSorterTrainer.java b/app/src/main/java/org/rssin/android/FeedSorterTrainer.java index 1289d1a..1f88a3e 100755 --- a/app/src/main/java/org/rssin/android/FeedSorterTrainer.java +++ b/app/src/main/java/org/rssin/android/FeedSorterTrainer.java @@ -2,30 +2,28 @@ 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)
+ private FeedSorterProvider sorterProvider;
+ public FeedSorterTrainer(FeedSorterProvider sorterProvider)
{
- this.sorter = sorter;
+ this.sorterProvider = sorterProvider;
}
@Override
public void run() {
for (int i = 0; i < 50; i++) {
Log.d("FeedSorterTrainer", "Training: round " + i);
- sorter.train();
+ sorterProvider.getFeedSorter().train();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
+
+ sorterProvider.save();
}
}
diff --git a/app/src/main/java/org/rssin/android/FilterActivity.java b/app/src/main/java/org/rssin/android/FilterActivity.java deleted file mode 100755 index 189fd55..0000000 --- a/app/src/main/java/org/rssin/android/FilterActivity.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.rssin.android; - -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.view.Menu; -import android.view.MenuItem; - -import com.android.volley.VolleyError; - -import org.rssin.listener.FallibleListener; -import org.rssin.rssin.SortedFeedItemContainer; -import org.rssin.rssin.FeedLoaderAndSorter; -import org.rssin.rssin.Filter; -import org.rssin.rssin.R; - -import java.io.IOException; -import java.util.List; - -public class FilterActivity extends ActionBarActivity { - - private FiltersList filtersList; - private Filter filter; - - private RecyclerView mRecyclerView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_filter); - mRecyclerView = (RecyclerView) findViewById(R.id.filter_feeditems); - RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this); - mRecyclerView.setLayoutManager(mLayoutManager); - - try { - filtersList = FiltersList.getInstance(this); - } catch (IOException e) { - Frontend.error(this, R.string.error_load_filters, e); - } - - Intent intent = getIntent(); - int filterHashCode = intent.getIntExtra("filter", -1); - - // @todo Check on -1? Shouldn't happen anyway. - filter = filtersList.getFilterFromHashCode(filterHashCode); - filter.ensureFeedSorter(InternalStorageProvider.getInstance(this)); - - setTitle(filter.getTitle()); - - FeedLoaderAndSorter loaderAndSorter = new FeedLoaderAndSorter(filter); - loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(this), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() { - @Override - public void onReceive(List<SortedFeedItemContainer> data) { - - FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data); - mRecyclerView.setAdapter(feedItemAdapter); - mRecyclerView.setHasFixedSize(true); - } - - @Override - public void onError(VolleyError error) { - Frontend.error(getBaseContext(), R.string.error_net_load); - } - }); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_filter, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - - if (id == R.id.action_settings) { - Intent intent = new Intent(getApplicationContext(), FilterSettingsActivity.class); - intent.putExtra("filter", filter.hashCode()); - startActivity(intent); - return true; - } - - return super.onOptionsItemSelected(item); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - try { - filter.storeFeedSorter(InternalStorageProvider.getInstance(this)); - } catch (Exception e) { - Frontend.warning(this, R.string.error_save_feedsorter, e); - } - } -} diff --git a/app/src/main/java/org/rssin/android/FiltersActivity.java b/app/src/main/java/org/rssin/android/FiltersActivity.java deleted file mode 100755 index a8e295c..0000000 --- a/app/src/main/java/org/rssin/android/FiltersActivity.java +++ /dev/null @@ -1,228 +0,0 @@ -package org.rssin.android; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.support.v7.app.ActionBarActivity; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.EditText; -import android.widget.ListView; -import android.widget.TextView; - -import org.rssin.rssin.Filter; -import org.rssin.rssin.R; - -import java.io.IOException; -import java.util.List; - -/** - * List of filters - * - * Short tap opens the list with current articles that the filter returns - * Long tap opens filter settings - * - * @author Camil Staps - */ -public class FiltersActivity extends ActionBarActivity { - - private FiltersList filtersList; - private ListView filtersView; - private FilterAdapter filterAdapter; - - private AdapterView.OnItemClickListener onFilterClickListener; - private AdapterView.OnItemLongClickListener onFilterLongClickListener; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.fragment_filters); - - filtersView = (ListView) findViewById(R.id.filters_list); - - try { - filtersList = FiltersList.getInstance(this); - } catch (IOException ex) { - Frontend.error(this, R.string.error_load_filters, ex); - finish(); - } - - filterAdapter = new FilterAdapter(this, R.layout.item_filter, filtersList.getFilters()); - filtersView.setAdapter(filterAdapter); - - setupListeners(); - } - - @Override - protected void onResume() { - super.onResume(); - - filterAdapter.notifyDataSetChanged(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_filters, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - - if (id == R.id.filters_action_add) { - openAddDialog(); - return true; - } - - return super.onOptionsItemSelected(item); - } - - /** - * Setup listeners for the list items - */ - private void setupListeners() { - onFilterClickListener = new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - Filter item = (Filter) parent.getItemAtPosition(position); - openFilter(item); - } - }; - onFilterLongClickListener = new AdapterView.OnItemLongClickListener() { - @Override - public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { - Filter item = (Filter) parent.getItemAtPosition(position); - openFilterSettings(item); - return true; - } - }; - - filtersView.setOnItemClickListener(onFilterClickListener); - filtersView.setOnItemLongClickListener(onFilterLongClickListener); - } - - /** - * Open dialog to create new filter - * For the moment, we temporarily disable rotating because we can't get it working otherwise. - * @todo make rotating possible - */ - public void openAddDialog() { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); - - AlertDialog.Builder alert = new AlertDialog.Builder(this); - - alert.setTitle("Add filter"); - alert.setMessage("Title:"); - - final EditText input = new EditText(this); - input.setFocusable(true); - input.requestFocus(); - - AlertDialog dialog = alert - .setView(input) - .setPositiveButton(getResources().getString(R.string.button_apply), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - String value = input.getText().toString(); - try { - Filter f = new Filter(value); - filtersList.getFilters().add(f); - filtersList.save(); - openFilterSettings(f); - } catch (Exception e) { - Frontend.error(getBaseContext(), R.string.error_save_filters, e); - } - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); - } - }) - .setNegativeButton(getResources().getString(R.string.button_cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); - } - }) - .create(); - - dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); - dialog.show(); - } - - public void openFilterSettings(Filter f) { - f.ensureFeeds(DefaultStorageProvider.getInstance(this)); - Intent intent = new Intent(getApplicationContext(), FilterSettingsActivity.class); - intent.putExtra("filter", f.hashCode()); - startActivity(intent); - } - - public void openFilter(Filter f) { - f.ensureFeeds(DefaultStorageProvider.getInstance(this)); - Intent intent = new Intent(getApplicationContext(), FilterActivity.class); - intent.putExtra("filter", f.hashCode()); - startActivity(intent); - } - - /** - * Custom ArrayAdapter to display filters with our own menu item - */ - private static class FilterAdapter extends SortedArrayAdapter<Filter> { - - Context context; - int layoutResourceId; - - public FilterAdapter(Context context, int resource, List<Filter> objects) { - super(context, resource, objects); - this.context = context; - layoutResourceId = resource; - items = objects; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View row = convertView; - FilterHolder holder = null; - - if (row == null) { - LayoutInflater inflater = ((Activity) context).getLayoutInflater(); - row = inflater.inflate(layoutResourceId, parent, false); - - holder = new FilterHolder(); - holder.title = (TextView) row.findViewById(R.id.filter_item_title); - holder.feeds = (TextView) row.findViewById(R.id.filter_item_feeds); - - row.setTag(holder); - } else { - holder = (FilterHolder) row.getTag(); - } - - Filter filter = items.get(position); - holder.title.setText(filter.getTitle()); - holder.feeds.setText(filter.getFeeds().size() + " " + context.getString(R.string.feeds)); - - return row; - } - - /** - * TextViews holder - */ - private static class FilterHolder { - TextView title; - TextView feeds; - } - } - -} diff --git a/app/src/main/java/org/rssin/android/HomeScreenActivity.java b/app/src/main/java/org/rssin/android/HomeScreenActivity.java index bbae149..797476a 100755 --- a/app/src/main/java/org/rssin/android/HomeScreenActivity.java +++ b/app/src/main/java/org/rssin/android/HomeScreenActivity.java @@ -1,33 +1,15 @@ package org.rssin.android;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.support.v7.app.ActionBarActivity;
-import android.support.v7.app.ActionBar;
+import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
-import android.os.Bundle;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.support.v4.widget.DrawerLayout;
-import com.android.volley.VolleyError;
-
-import org.rssin.listener.FallibleListener;
-import org.rssin.rssin.Feed;
-import org.rssin.rssin.Filter;
import org.rssin.rssin.R;
-import org.rssin.rssin.SortedFeedItemContainer;
-import org.rssin.rssin.UnifiedFilterLoader;
-
-import java.io.IOException;
-import java.util.List;
public class HomeScreenActivity extends ActionBarActivity
diff --git a/app/src/main/java/org/rssin/android/NavigationDrawerAllFeedsFragment.java b/app/src/main/java/org/rssin/android/NavigationDrawerAllFeedsFragment.java index 15edbed..b7a0d73 100755 --- a/app/src/main/java/org/rssin/android/NavigationDrawerAllFeedsFragment.java +++ b/app/src/main/java/org/rssin/android/NavigationDrawerAllFeedsFragment.java @@ -13,12 +13,10 @@ import android.view.ViewGroup; import com.android.volley.VolleyError;
import org.rssin.listener.FallibleListener;
-import org.rssin.rssin.Filter;
+import org.rssin.rssin.FeedLoaderAndSorter;
import org.rssin.rssin.R;
import org.rssin.rssin.SortedFeedItemContainer;
-import org.rssin.rssin.UnifiedFilterLoader;
-import java.io.IOException;
import java.util.List;
/**
@@ -44,38 +42,27 @@ public class NavigationDrawerAllFeedsFragment extends Fragment { RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(context);
mRecyclerView.setLayoutManager(mLayoutManager);
- try {
- FiltersList filtersList = FiltersList.getInstance(context);
-
- for(Filter filter : filtersList.getFilters()) {
- filter.ensureFeedSorter(DefaultStorageProvider.getInstance(context));
- filter.ensureFeeds(DefaultStorageProvider.getInstance(context));
+ /**
+ * @todo Load feeds in separate thread so that the UI is immediately available
+ *
+ * @todo Now, feed items are only returned after *all* feeds have been loaded. With many
+ * filters that may take a while, so it would be preferable to return intermediate
+ * results. We could do this for example with {@link org.rssin.listener.RealtimeListener}
+ */
+ FeedLoaderAndSorter loaderAndSorter = new FeedLoaderAndSorter(FeedsList.getInstance().getFeeds());
+ loaderAndSorter.getFilteredFeedItems(context, new VolleyFetcher(context), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() {
+ @Override
+ public void onReceive(List<SortedFeedItemContainer> data) {
+ FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data);
+ mRecyclerView.setAdapter(feedItemAdapter);
+ mRecyclerView.setHasFixedSize(true);
}
- /**
- * @todo Load feeds in separate thread so that the UI is immediately available
- *
- * @todo Now, feed items are only returned after *all* feeds have been loaded. With many
- * filters that may take a while, so it would be preferable to return intermediate
- * results. We could do this for example with {@link org.rssin.listener.RealtimeListener}
- */
- UnifiedFilterLoader loaderAndSorter = new UnifiedFilterLoader(filtersList.getFilters());
- loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(context), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() {
- @Override
- public void onReceive(List<SortedFeedItemContainer> data) {
- FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data);
- mRecyclerView.setAdapter(feedItemAdapter);
- mRecyclerView.setHasFixedSize(true);
- }
-
- @Override
- public void onError(VolleyError error) {
- Frontend.error(context, R.string.error_net_load);
- }
- });
- } catch (IOException e) {
- Frontend.error(context, R.string.error_load_filters, e);
- }
+ @Override
+ public void onError(VolleyError error) {
+ Frontend.error(context, R.string.error_net_load);
+ }
+ });
return rootView;
}
diff --git a/app/src/main/java/org/rssin/android/NavigationDrawerFeedFragment.java b/app/src/main/java/org/rssin/android/NavigationDrawerFeedFragment.java index 901d854..0f33aca 100755 --- a/app/src/main/java/org/rssin/android/NavigationDrawerFeedFragment.java +++ b/app/src/main/java/org/rssin/android/NavigationDrawerFeedFragment.java @@ -14,13 +14,13 @@ import com.android.volley.VolleyError; import org.rssin.listener.FallibleListener;
import org.rssin.rssin.Feed;
-import org.rssin.rssin.Filter;
+import org.rssin.rssin.FeedLoaderAndSorter;
import org.rssin.rssin.R;
import org.rssin.rssin.SortedFeedItemContainer;
-import org.rssin.rssin.UnifiedFilterLoader;
import java.io.IOException;
import java.util.List;
+import java.util.ArrayList;
/**
* @author Jos.
@@ -64,38 +64,30 @@ public class NavigationDrawerFeedFragment extends Fragment { feed = (Feed) args.get(ARG_FEED_NAME);
- try {
- FiltersList filtersList = FiltersList.getInstance(context);
-
- for(Filter filter : filtersList.getFilters()) {
- filter.ensureFeedSorter(DefaultStorageProvider.getInstance(context));
- filter.ensureFeeds(DefaultStorageProvider.getInstance(context));
+ List<Feed> singleFeedList = new ArrayList<Feed>();
+ singleFeedList.add(feed);
+
+ /**
+ * @todo Load feeds in separate thread so that the UI is immediately available
+ *
+ * @todo Now, feed items are only returned after *all* feeds have been loaded. With many
+ * filters that may take a while, so it would be preferable to return intermediate
+ * results. We could do this for example with {@link org.rssin.listener.RealtimeListener}
+ */
+ FeedLoaderAndSorter loaderAndSorter = new FeedLoaderAndSorter(singleFeedList);
+ loaderAndSorter.getFilteredFeedItems(context, new VolleyFetcher(context), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() {
+ @Override
+ public void onReceive(List<SortedFeedItemContainer> data) {
+ FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data);
+ mRecyclerView.setAdapter(feedItemAdapter);
+ mRecyclerView.setHasFixedSize(true);
}
- /**
- * @todo Load feeds in separate thread so that the UI is immediately available
- *
- * @todo Now, feed items are only returned after *all* feeds have been loaded. With many
- * filters that may take a while, so it would be preferable to return intermediate
- * results. We could do this for example with {@link org.rssin.listener.RealtimeListener}
- */
- UnifiedFilterLoader loaderAndSorter = new UnifiedFilterLoader(filtersList.getFilters());
- loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(context), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() {
- @Override
- public void onReceive(List<SortedFeedItemContainer> data) {
- FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data);
- mRecyclerView.setAdapter(feedItemAdapter);
- mRecyclerView.setHasFixedSize(true);
- }
-
- @Override
- public void onError(VolleyError error) {
- Frontend.error(context, R.string.error_net_load);
- }
- });
- } catch (IOException e) {
- Frontend.error(context, R.string.error_load_filters, e);
- }
+ @Override
+ public void onError(VolleyError error) {
+ Frontend.error(context, R.string.error_net_load);
+ }
+ });
return rootView;
}
diff --git a/app/src/main/java/org/rssin/android/NavigationDrawerFilterFragment.java b/app/src/main/java/org/rssin/android/NavigationDrawerFilterFragment.java index ab9d458..74be14a 100755 --- a/app/src/main/java/org/rssin/android/NavigationDrawerFilterFragment.java +++ b/app/src/main/java/org/rssin/android/NavigationDrawerFilterFragment.java @@ -17,7 +17,6 @@ import org.rssin.rssin.FeedLoaderAndSorter; import org.rssin.rssin.Filter;
import org.rssin.rssin.R;
import org.rssin.rssin.SortedFeedItemContainer;
-import org.rssin.rssin.UnifiedFilterLoader;
import java.io.IOException;
import java.util.List;
@@ -65,7 +64,6 @@ public class NavigationDrawerFilterFragment extends Fragment { e.printStackTrace();
}
- filter.ensureFeedSorter(DefaultStorageProvider.getInstance(context));
filter.ensureFeeds(DefaultStorageProvider.getInstance(context));
/**
@@ -75,8 +73,8 @@ public class NavigationDrawerFilterFragment extends Fragment { * filters that may take a while, so it would be preferable to return intermediate
* results. We could do this for example with {@link org.rssin.listener.RealtimeListener}
*/
- FeedLoaderAndSorter loaderAndSorter = new FeedLoaderAndSorter(filter);
- loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(context), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() {
+ FeedLoaderAndSorter loaderAndSorter = new FeedLoaderAndSorter(filter.getFeeds());
+ loaderAndSorter.getFilteredFeedItems(context, new VolleyFetcher(context), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() {
@Override
public void onReceive(List<SortedFeedItemContainer> data) {
FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data);
diff --git a/app/src/main/java/org/rssin/android/NavigationDrawerManageFiltersFragment.java b/app/src/main/java/org/rssin/android/NavigationDrawerManageFiltersFragment.java index d82aaaa..405d7be 100755 --- a/app/src/main/java/org/rssin/android/NavigationDrawerManageFiltersFragment.java +++ b/app/src/main/java/org/rssin/android/NavigationDrawerManageFiltersFragment.java @@ -21,13 +21,8 @@ import android.widget.EditText; import android.widget.ListView;
import android.widget.TextView;
-import com.android.volley.VolleyError;
-
-import org.rssin.listener.FallibleListener;
import org.rssin.rssin.Filter;
import org.rssin.rssin.R;
-import org.rssin.rssin.SortedFeedItemContainer;
-import org.rssin.rssin.UnifiedFilterLoader;
import java.io.IOException;
import java.util.List;
diff --git a/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java b/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java index 2818a08..dbfcc9a 100755 --- a/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java +++ b/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java @@ -86,7 +86,11 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage if (serialized == null) { throw new IOException("No sharedPreference with key " + key.toString() + " and class " + className.getName()); } - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.decode(serialized.getBytes(), Base64.DEFAULT))); + + byte[] bytes = serialized.getBytes(); + byte[] decoded = Base64.decode(bytes, Base64.DEFAULT); + + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(decoded)); Object obj = ois.readObject(); return (Storable) className.cast(obj); } @@ -97,10 +101,6 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage .edit() .remove(className.getName()) .apply(); - - if (className == Feed.class) { - removeFeed(key); - } } @Override @@ -170,14 +170,14 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage Set<String> names = context.getSharedPreferences(ADMIN_PREF_KEY, Context.MODE_PRIVATE).getStringSet("feeds", new HashSet<String>()); if (names.isEmpty() && !context.getSharedPreferences(ADMIN_PREF_KEY, Context.MODE_PRIVATE).getBoolean("firstload", false)) { String[] feedsList = context.getResources().getStringArray(R.array.default_feeds); - for (String url : feedsList) { + /*for (String url : feedsList) { try { Feed f = new Feed(url); f.store(this); } catch (Exception e) { Log.w("SPSP", "Couldn't add " + url, e); } - } + }*/ context.getSharedPreferences(ADMIN_PREF_KEY, Context.MODE_PRIVATE).edit().putBoolean("firstload", true).apply(); names = context.getSharedPreferences(ADMIN_PREF_KEY, Context.MODE_PRIVATE).getStringSet("feeds", new HashSet<String>()); } diff --git a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java index 3211325..a317a27 100755 --- a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java +++ b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java @@ -1,5 +1,8 @@ package org.rssin.rssin;
+import android.content.Context;
+
+import org.rssin.android.FeedSorterProvider;
import org.rssin.http.Fetcher;
import org.rssin.listener.FallibleListener;
import org.rssin.listener.Listener;
@@ -16,10 +19,10 @@ import java.util.List; * @todo javadoc
*/
public class FeedLoaderAndSorter {
- private Filter filter;
+ private final List<Feed> feeds;
- public FeedLoaderAndSorter(Filter filter) {
- this.filter = filter;
+ public FeedLoaderAndSorter(List<Feed> feeds) {
+ this.feeds = feeds;
}
/**
@@ -27,19 +30,19 @@ public class FeedLoaderAndSorter { * @param fetcher HTTP Fetcher
* @param listener Listener for when the fetcher finishes
*/
- public void getFilteredFeedItems(Fetcher fetcher, final Listener<List<SortedFeedItemContainer>> listener)
+ public void getFilteredFeedItems(Context context, Fetcher fetcher, final Listener<List<SortedFeedItemContainer>> listener)
{
final List<SortedFeedItemContainer> resultingItems = new ArrayList<>();
- final Counter counter = new Counter(filter.getFeeds().size());
- final FeedSorter sorter = filter.getFeedSorter();
+ final Counter counter = new Counter(feeds.size());
+ final FeedSorter sorter = FeedSorterProvider.getInstance(context).getFeedSorter();
- for (Feed feed : filter.getFeeds()) {
+ for (Feed feed : feeds) {
final FeedLoader loader = new FeedLoader(feed.getURL());
loader.fetchXML(fetcher, new FallibleListener<Object, Object>() {
@Override
public void onReceive(Object data) {
for (FeedItem item : loader.getFeed().getPosts()) {
- resultingItems.add(new SortedFeedItemContainer(item, filter));
+ resultingItems.add(new SortedFeedItemContainer(item));
}
List<SortedFeedItemContainer> sorted = sorter.sortItems(resultingItems);
diff --git a/app/src/main/java/org/rssin/rssin/Filter.java b/app/src/main/java/org/rssin/rssin/Filter.java index e7e0158..283bde0 100755 --- a/app/src/main/java/org/rssin/rssin/Filter.java +++ b/app/src/main/java/org/rssin/rssin/Filter.java @@ -43,17 +43,6 @@ public class Filter implements Storable, Comparable<Filter>, Jsonable { */ private Object storageKey; - /** - * The FeedSorter for this filter - * Since this object is fairly large, serialisation takes too long to save it with the filter - * itself, and serialise the FeedSorter every time we update our filter's settings. Therefore, - * We define this attribute to be transient, and require the programmer to call - * {@link this#ensureFeedSorter(StorageProvider)} before using this attribute. - * - * @see this#ensureFeedSorter(StorageProvider) - */ - private transient FeedSorter feedSorter; - public Filter() { feedHashCodes = new ArrayList<>(); feeds = new ArrayList<>(); @@ -90,40 +79,10 @@ public class Filter implements Storable, Comparable<Filter>, Jsonable { this.title = title.trim(); } - /** - * Be sure to call {@link this#ensureFeedSorter(StorageProvider)} before calling this getter. - * @return - */ - public FeedSorter getFeedSorter() { - return feedSorter; - } - public Object getStorageKey() { return storageKey; } - /** - * Ensure that there is a feedSorter linked to this object - * Because the feedSorter attribute is transient (if not, serialisation for changing settings - * takes too long), we need to manually ensure we get the FeedSorter as well every time we need - * it. It is the programmer's responsibility to call this method. - * @param storageProvider - */ - public synchronized void ensureFeedSorter(StorageProvider storageProvider) { - if (storageKey == null) { - storageKey = storageProvider.uniqueKey(); - } - - try { - feedSorter = (FeedSorter) storageProvider.fetch(storageKey, FeedSorter.class); - } catch (Exception e) { - feedSorter = new FeedSorter(); - try { - storageProvider.store(storageKey, feedSorter); - } catch (Exception e1) {} - } - } - public synchronized void ensureFeeds(FeedStorageProvider storageProvider) { List<Feed> all_feeds = storageProvider.allFeeds(); feeds = new ArrayList<>(); @@ -161,18 +120,6 @@ public class Filter implements Storable, Comparable<Filter>, Jsonable { storageProvider.removeFilter(storageKey); } - /** - * Save the FeedSorter of this Filter - * This is done in a separate thread because it takes too long to do in a main thread. This - * also means that you cannot rely on the FeedSorter being saved when this method returns. - * @param storageProvider - * @throws Exception - */ - public synchronized void storeFeedSorter(StorageProvider storageProvider) { - Thread thread = new Thread(new FeedSorterStorer(storageKey, storageProvider, feedSorter)); - thread.start(); - } - @Override public int compareTo(@Nullable Filter another) { return another == null ? -1 : title.compareTo(another.title); @@ -193,27 +140,4 @@ public class Filter implements Storable, Comparable<Filter>, Jsonable { feedHashCodes = JsonSerializer.integersListFromJson(json.getJSONArray("feedHashCodes")); storageKey = json.getString("storageKey"); } - - private class FeedSorterStorer implements Runnable { - private final Object storageKey; - private final StorageProvider storageProvider; - private final FeedSorter feedSorter; - - public FeedSorterStorer(Object storageKey, StorageProvider storageProvider, FeedSorter feedSorter) { - this.storageKey = storageKey; - this.storageProvider = storageProvider; - this.feedSorter = feedSorter; - } - - @Override - public void run() { - ensureFeedSorter(storageProvider); - try { - storageProvider.store(storageKey, feedSorter); - } catch (Exception e) { - Log.e("Filter", "Failed to store FeedSorter", e); - } - } - } - } diff --git a/app/src/main/java/org/rssin/rssin/SortedFeedItemContainer.java b/app/src/main/java/org/rssin/rssin/SortedFeedItemContainer.java index 913a120..2a69bfa 100755 --- a/app/src/main/java/org/rssin/rssin/SortedFeedItemContainer.java +++ b/app/src/main/java/org/rssin/rssin/SortedFeedItemContainer.java @@ -1,5 +1,8 @@ package org.rssin.rssin;
+import android.content.Context;
+
+import org.rssin.android.FeedSorterProvider;
import org.rssin.android.FiltersList;
import org.rssin.neurons.FeedSorter;
import org.rssin.neurons.Feedback;
@@ -12,13 +15,11 @@ import java.io.Serializable; */
public class SortedFeedItemContainer implements Comparable<SortedFeedItemContainer>, Serializable {
private FeedItem feeditem;
- private int filterHashCode;
private long score;
- public SortedFeedItemContainer(FeedItem feeditem, Filter filter)
+ public SortedFeedItemContainer(FeedItem feeditem)
{
this.feeditem = feeditem;
- this.filterHashCode = filter.hashCode();
this.setScore(-1);
}
@@ -26,13 +27,6 @@ public class SortedFeedItemContainer implements Comparable<SortedFeedItemContain return feeditem;
}
- public FeedSorter getSorter() {
- FiltersList provider = FiltersList.getInstance();
- Filter f = provider.getFilterFromHashCode(filterHashCode);
-
- return f.getFeedSorter();
- }
-
public long getScore() {
if(score == -1)
{
@@ -42,9 +36,9 @@ public class SortedFeedItemContainer implements Comparable<SortedFeedItemContain return score;
}
- public void feedback(Feedback feedback)
+ public void feedback(Context context, Feedback feedback)
{
- getSorter().feedback(getFeeditem(), feedback);
+ FeedSorterProvider.getInstance(context).getFeedSorter().feedback(getFeeditem(), feedback);
}
public void setScore(long score) {
@@ -53,6 +47,6 @@ public class SortedFeedItemContainer implements Comparable<SortedFeedItemContain @Override
public int compareTo(SortedFeedItemContainer another) {
- return (int)(this.getScore() - another.getScore());
+ 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 deleted file mode 100755 index 619a152..0000000 --- a/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.rssin.rssin;
-
-import org.rssin.http.Fetcher;
-import org.rssin.listener.Listener;
-import org.rssin.listener.RealtimeListener;
-
-import java.util.ArrayList;
-import java.util.Collections;
-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<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<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<SortedFeedItemContainer>>() {
- @Override
- public void onReceive(List<SortedFeedItemContainer> data) {
- resultingItems.addAll(data);
-
- if (counter.decr().isZero() || listener.getClass() == RealtimeListener.class) {
- 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);
-
- 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/java/org/rssin/rssin/dummy/DummyContent.java b/app/src/main/java/org/rssin/rssin/dummy/DummyContent.java deleted file mode 100755 index 059f859..0000000 --- a/app/src/main/java/org/rssin/rssin/dummy/DummyContent.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.rssin.rssin.dummy;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Helper class for providing sample content for user interfaces created by
- * Android template wizards.
- * <p/>
- * TODO: Replace all uses of this class before publishing your app.
- */
-public class DummyContent {
-
- /**
- * An array of sample (dummy) items.
- */
- public static List<DummyItem> ITEMS = new ArrayList<DummyItem>();
-
- /**
- * A map of sample (dummy) items, by ID.
- */
- public static Map<String, DummyItem> ITEM_MAP = new HashMap<String, DummyItem>();
-
- static {
- // Add 3 sample items.
- addItem(new DummyItem("1", "Item 1"));
- addItem(new DummyItem("2", "Item 2"));
- addItem(new DummyItem("3", "Item 3"));
- }
-
- private static void addItem(DummyItem item) {
- ITEMS.add(item);
- ITEM_MAP.put(item.id, item);
- }
-
- /**
- * A dummy item representing a piece of content.
- */
- public static class DummyItem {
- public String id;
- public String content;
-
- public DummyItem(String id, String content) {
- this.id = id;
- this.content = content;
- }
-
- @Override
- public String toString() {
- return content;
- }
- }
-}
diff --git a/app/src/main/res/layout/activity_filter.xml b/app/src/main/res/layout/activity_filter.xml index 7475330..6318a31 100755 --- a/app/src/main/res/layout/activity_filter.xml +++ b/app/src/main/res/layout/activity_filter.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" -tools:context="org.rssin.android.FilterActivity"> +tools:context="org.rssin.android.HomeScreenActivity"> <!-- A RecyclerView with some commonly used attributes --> <android.support.v7.widget.RecyclerView diff --git a/app/src/main/res/layout/fragment_filters.xml b/app/src/main/res/layout/fragment_filters.xml index c948344..fad91ad 100644..100755 --- a/app/src/main/res/layout/fragment_filters.xml +++ b/app/src/main/res/layout/fragment_filters.xml @@ -7,7 +7,7 @@ android:paddingRight="0dp" android:paddingTop="0dp" android:paddingBottom="0dp" - tools:context="org.rssin.android.FiltersActivity"> + tools:context="org.rssin.android.HomeScreenActivity"> <ListView android:id="@+id/filters_list" diff --git a/app/src/main/res/menu/menu_filter.xml b/app/src/main/res/menu/menu_filter.xml index aaf1ca1..86cfe5d 100644..100755 --- a/app/src/main/res/menu/menu_filter.xml +++ b/app/src/main/res/menu/menu_filter.xml @@ -1,6 +1,6 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" tools:context="org.rssin.android.FilterActivity"> + xmlns:tools="http://schemas.android.com/tools" tools:context="org.rssin.android.HomeScreenActivity"> <item android:id="@+id/action_settings" android:title="@string/action_settings" android:orderInCategory="100" app:showAsAction="never" /> </menu> |