aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
authorCamil Staps2015-05-30 16:31:31 +0200
committerCamil Staps2015-05-30 16:31:31 +0200
commit91620ce7c5451a5e7538c7524440ee015a42fd81 (patch)
tree10b8bdae0a44e3532a28e1c12ccdfa05c15f6fd7 /app/src/main/java
parentFixed app title issue (diff)
Using JSON for serialization of keywords, feeds and filters
Diffstat (limited to 'app/src/main/java')
-rwxr-xr-xapp/src/main/java/org/rssin/android/FilterSettingsActivity.java32
-rwxr-xr-xapp/src/main/java/org/rssin/android/FiltersActivity.java12
-rw-r--r--app/src/main/java/org/rssin/android/InternalStorageProvider.java10
-rw-r--r--app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java33
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/FeedSorter.java2
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java2
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/NeuralNetwork.java2
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/Neuron.java2
-rwxr-xr-xapp/src/main/java/org/rssin/rssin/Feed.java42
-rwxr-xr-xapp/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java7
-rwxr-xr-xapp/src/main/java/org/rssin/rssin/Filter.java55
-rw-r--r--app/src/main/java/org/rssin/rssin/Keyword.java32
-rw-r--r--app/src/main/java/org/rssin/serialization/JsonSerializer.java59
-rw-r--r--app/src/main/java/org/rssin/serialization/Jsonable.java15
-rwxr-xr-xapp/src/main/java/org/rssin/serialization/SerializationTools.java (renamed from app/src/main/java/org/rssin/tools/SerializationTools.java)2
-rw-r--r--app/src/main/java/org/rssin/storage/FilterStorageProvider.java13
-rw-r--r--app/src/main/java/org/rssin/storage/StorageProvider.java7
17 files changed, 287 insertions, 40 deletions
diff --git a/app/src/main/java/org/rssin/android/FilterSettingsActivity.java b/app/src/main/java/org/rssin/android/FilterSettingsActivity.java
index 0d4af45..11aed6d 100755
--- a/app/src/main/java/org/rssin/android/FilterSettingsActivity.java
+++ b/app/src/main/java/org/rssin/android/FilterSettingsActivity.java
@@ -101,7 +101,7 @@ public class FilterSettingsActivity extends ActionBarActivity {
case R.id.filter_settings_action_delete:
filtersList.getFilters().remove(filter);
try {
- filtersList.save();
+ filter.delete(DefaultStorageProvider.getInstance());
finish();
} catch (Exception e) {
Frontend.error(this, R.string.error_delete_filter, e);
@@ -227,6 +227,7 @@ public class FilterSettingsActivity extends ActionBarActivity {
/**
* @todo nicer selected feed layout
+ * @todo deselecting feeds doesn't work
*/
feedsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
@@ -256,17 +257,23 @@ public class FilterSettingsActivity extends ActionBarActivity {
try {
URL url = new URL(value);
Feed feed = new Feed(url);
- FeedsList.getInstance().getFeeds().add(feed);
- filter.getFeedHashCodes().add(feed.hashCode());
-
try {
- filter.store(DefaultStorageProvider.getInstance());
feed.store(DefaultStorageProvider.getInstance());
- feedAdapter.notifyDataSetChanged();
- editText.setText("");
+ FeedsList.getInstance().getFeeds().add(feed);
+ filter.getFeedHashCodes().add(feed.hashCode());
+
+ try {
+ filter.store(DefaultStorageProvider.getInstance());
+ feed.store(DefaultStorageProvider.getInstance());
+ feedAdapter.notifyDataSetChanged();
+ editText.setText("");
+ } catch (Exception e) {
+ Frontend.error(getActivity(), R.string.error_save_filters, e);
+ filter.getFeeds().remove(feed);
+ }
} catch (Exception e) {
- Frontend.error(getActivity(), R.string.error_save_filters, e);
- filter.getFeeds().remove(feed);
+ Frontend.error(getActivity(), R.string.error_save_feeds, e);
+ FeedsList.getInstance().getFeeds().remove(feed);
}
} catch (MalformedURLException e) {
Frontend.info(getActivity(), R.string.error_invalid_url, e);
@@ -275,12 +282,7 @@ public class FilterSettingsActivity extends ActionBarActivity {
});
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- builder.setMessage(R.string.filter_settings_feeds)
- .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- // @todo FIRE ZE MISSILES!
- }
- });
+ builder.setMessage(R.string.filter_settings_feeds).setPositiveButton(R.string.button_ok, null);
builder.setView(view);
return builder.create();
diff --git a/app/src/main/java/org/rssin/android/FiltersActivity.java b/app/src/main/java/org/rssin/android/FiltersActivity.java
index 35bd533..6efb8a9 100755
--- a/app/src/main/java/org/rssin/android/FiltersActivity.java
+++ b/app/src/main/java/org/rssin/android/FiltersActivity.java
@@ -37,6 +37,7 @@ public class FiltersActivity extends ActionBarActivity {
private FiltersList filtersList;
private ListView filtersView;
+ private FilterAdapter filterAdapter;
private AdapterView.OnItemClickListener onFilterClickListener;
private AdapterView.OnItemLongClickListener onFilterLongClickListener;
@@ -55,13 +56,20 @@ public class FiltersActivity extends ActionBarActivity {
finish();
}
- final FilterAdapter adapter = new FilterAdapter(this, R.layout.item_filter, filtersList.getFilters());
- filtersView.setAdapter(adapter);
+ 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;
diff --git a/app/src/main/java/org/rssin/android/InternalStorageProvider.java b/app/src/main/java/org/rssin/android/InternalStorageProvider.java
index 91534b3..c5a7bc1 100644
--- a/app/src/main/java/org/rssin/android/InternalStorageProvider.java
+++ b/app/src/main/java/org/rssin/android/InternalStorageProvider.java
@@ -56,6 +56,11 @@ class InternalStorageProvider implements StorageProvider<String, Storable>, Filt
return fetchFromFilename(getFilename(key, className));
}
+ @Override
+ public void remove(String key, Class className) throws Exception {
+ throw new UnsupportedOperationException("Not implemented yet.");
+ }
+
public Storable fetchFromFilename(String fileName) throws ClassCastException, FileNotFoundException, IOException {
FileInputStream fis = context.openFileInput(fileName);
ObjectInputStream ois = new ObjectInputStream(fis);
@@ -118,6 +123,11 @@ class InternalStorageProvider implements StorageProvider<String, Storable>, Filt
}
@Override
+ public void storeFilter(String key, Filter filter) throws Exception {
+ throw new UnsupportedOperationException("Not implemented yet.");
+ }
+
+ @Override
public Filter getFilter(String key) {
try {
return (Filter) fetch(key, Filter.class);
diff --git a/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java b/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java
index 161e1c6..4cc9386 100644
--- a/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java
+++ b/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java
@@ -3,6 +3,7 @@ package org.rssin.android;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;
+import android.util.Log;
import org.rssin.rssin.Feed;
import org.rssin.rssin.Filter;
@@ -70,9 +71,10 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage
oos.close();
String string = Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
- SharedPreferences.Editor editor = context.getSharedPreferences(key.toString(), Context.MODE_PRIVATE).edit();
- editor.putString(element.getClass().getName(), string);
- boolean works = editor.commit();
+ context.getSharedPreferences(key.toString(), Context.MODE_PRIVATE)
+ .edit()
+ .putString(element.getClass().getName(), string)
+ .apply();
if (element.getClass() == Filter.class) {
storeFilterKey(key);
@@ -88,19 +90,25 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage
throw new IOException("No sharedPreference with key " + key.toString() + " and class " + className.getName());
}
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.decode(serialized, Base64.DEFAULT)));
- return (Storable) className.cast(ois.readObject());
+ Object obj = ois.readObject();
+ return (Storable) className.cast(obj);
}
- protected void remove(Object key, Class className) {
+ @Override
+ public void remove(Object key, Class className) {
context.getSharedPreferences(key.toString(), Context.MODE_PRIVATE)
.edit()
.remove(className.getName())
.apply();
+
+ if (className == Feed.class) {
+ removeFeed(key);
+ }
}
@Override
public Object uniqueKey() {
- return "_" + Long.toString(System.currentTimeMillis());
+ return Long.toString(System.currentTimeMillis());
}
@Override
@@ -119,6 +127,12 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage
}
@Override
+ public void storeFilter(Object key, Filter filter) throws Exception {
+ storeFilterKey(key);
+ store(key, filter);
+ }
+
+ @Override
public Filter getFilter(Object key) {
try {
return (Filter) fetch(key.toString(), Filter.class);
@@ -131,11 +145,17 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage
public void removeFilter(Object key) {
SharedPreferences sharedPreferences = context.getSharedPreferences(ADMIN_PREF_KEY, Context.MODE_PRIVATE);
Set<String> names = new HashSet<>(sharedPreferences.getStringSet("filters", new HashSet<String>()));
+ for (String name : names)
+ Log.d("SPSP", "Old name: " + name);
+ Log.d("SPSP", "Removing name " + key.toString());
names.remove(key.toString());
+ for (String name : names)
+ Log.d("SPSP", "New name: " + name);
sharedPreferences
.edit()
.putStringSet("filters", names)
.apply();
+ remove(key, Filter.class);
}
/**
@@ -171,6 +191,7 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage
try {
return (Feed) fetch(key.toString(), Feed.class);
} catch (Exception e) {
+ Log.e("SPSP", "Couldn't get feed", e);
return null;
}
}
diff --git a/app/src/main/java/org/rssin/neurons/FeedSorter.java b/app/src/main/java/org/rssin/neurons/FeedSorter.java
index fe1e998..3d420a6 100755
--- a/app/src/main/java/org/rssin/neurons/FeedSorter.java
+++ b/app/src/main/java/org/rssin/neurons/FeedSorter.java
@@ -2,7 +2,7 @@ package org.rssin.neurons;
import org.rssin.rss.FeedItem;
import org.rssin.storage.Storable;
-import org.rssin.tools.SerializationTools;
+import org.rssin.serialization.SerializationTools;
import java.io.IOException;
import java.util.ArrayList;
diff --git a/app/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java b/app/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java
index 0f5c31b..ece53a8 100755
--- a/app/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java
+++ b/app/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java
@@ -1,6 +1,6 @@
package org.rssin.neurons;
-import org.rssin.tools.SerializationTools;
+import org.rssin.serialization.SerializationTools;
import java.io.IOException;
import java.io.Serializable;
diff --git a/app/src/main/java/org/rssin/neurons/NeuralNetwork.java b/app/src/main/java/org/rssin/neurons/NeuralNetwork.java
index 2cbe284..c990be9 100755
--- a/app/src/main/java/org/rssin/neurons/NeuralNetwork.java
+++ b/app/src/main/java/org/rssin/neurons/NeuralNetwork.java
@@ -2,7 +2,7 @@ package org.rssin.neurons;
import android.annotation.SuppressLint;
-import org.rssin.tools.SerializationTools;
+import org.rssin.serialization.SerializationTools;
import java.io.IOException;
import java.io.Serializable;
diff --git a/app/src/main/java/org/rssin/neurons/Neuron.java b/app/src/main/java/org/rssin/neurons/Neuron.java
index 6a4970a..203a450 100755
--- a/app/src/main/java/org/rssin/neurons/Neuron.java
+++ b/app/src/main/java/org/rssin/neurons/Neuron.java
@@ -1,6 +1,6 @@
package org.rssin.neurons;
-import org.rssin.tools.SerializationTools;
+import org.rssin.serialization.SerializationTools;
import java.io.IOException;
import java.io.Serializable;
diff --git a/app/src/main/java/org/rssin/rssin/Feed.java b/app/src/main/java/org/rssin/rssin/Feed.java
index 77e58c0..55d0e5d 100755
--- a/app/src/main/java/org/rssin/rssin/Feed.java
+++ b/app/src/main/java/org/rssin/rssin/Feed.java
@@ -1,19 +1,25 @@
package org.rssin.rssin;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.rssin.serialization.Jsonable;
import org.rssin.storage.Storable;
import org.rssin.storage.StorageProvider;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Feed holder
* @author Camil Staps
- *
- * @todo Write read & writeObject with JSON or so to make it easier to change this class later
*/
-public class Feed implements Storable, Comparable<Feed> {
- private static int serialVersionUID = 0;
+public class Feed implements Storable, Comparable<Feed>, Jsonable {
+ private static final long serialVersionUID = 0;
/**
* This feed does not have any information about the current status of the feed.
@@ -47,6 +53,14 @@ public class Feed implements Storable, Comparable<Feed> {
this.title = title;
}
+ private void writeObject(ObjectOutputStream stream) throws JSONException, IOException {
+ stream.writeObject(toJson().toString());
+ }
+
+ private void readObject(ObjectInputStream stream) throws JSONException, IOException, ClassNotFoundException {
+ fromJson(new JSONObject((String) stream.readObject()));
+ }
+
public String getTitle() {
return title;
}
@@ -117,4 +131,24 @@ public class Feed implements Storable, Comparable<Feed> {
public int compareTo(Feed another) {
return title.compareTo(another.title);
}
+
+ @Override
+ public JSONObject toJson() throws JSONException {
+ JSONObject json = new JSONObject();
+ json.put("title", title);
+ json.put("url", url.toString());
+ json.put("storageKey", storageKey.toString());
+ return json;
+ }
+
+ @Override
+ public void fromJson(JSONObject json) throws JSONException {
+ title = json.getString("title");
+ storageKey = json.getString("storageKey");
+ try {
+ url = new URL(json.getString("url"));
+ } catch (MalformedURLException e) {
+ throw new JSONException("Invalid URL");
+ }
+ }
}
diff --git a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java
index e1fbbab..745e944 100755
--- a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java
+++ b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java
@@ -81,6 +81,13 @@ public class FeedLoaderAndSorter {
}
}
+ /**
+ * @todo Why do we check on author?
+ * @todo Should we check only on whole words / give whole word occurences higher relevance?
+ * @todo At least only whole words for categories; otherwise Port connaisseurs will read only Sport news
+ * @param item
+ * @return
+ */
private boolean matchesKeyword(FeedItem item)
{
for(Keyword keyword : filter.getKeywords())
diff --git a/app/src/main/java/org/rssin/rssin/Filter.java b/app/src/main/java/org/rssin/rssin/Filter.java
index 514d845..7b2c54e 100755
--- a/app/src/main/java/org/rssin/rssin/Filter.java
+++ b/app/src/main/java/org/rssin/rssin/Filter.java
@@ -3,11 +3,20 @@ package org.rssin.rssin;
import android.text.TextUtils;
import android.util.Log;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
import org.rssin.neurons.FeedSorter;
+import org.rssin.serialization.JsonSerializer;
+import org.rssin.serialization.Jsonable;
import org.rssin.storage.FeedStorageProvider;
+import org.rssin.storage.FilterStorageProvider;
import org.rssin.storage.Storable;
import org.rssin.storage.StorageProvider;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
@@ -17,7 +26,7 @@ import java.util.List;
*
* @todo Write read & writeObject with JSON or so to make it easier to change this class later
*/
-public class Filter implements Storable, Comparable<Filter> {
+public class Filter implements Storable, Comparable<Filter>, Jsonable {
private static final long serialVersionUID = 0;
@@ -25,9 +34,9 @@ public class Filter implements Storable, Comparable<Filter> {
* A filter is a list of Feeds with a list of Keywords. A title can be added as well.
* The List of Feeds is transient. We only store a list of Feed hashcodes
*/
- private final List<Integer> feedHashCodes;
+ private List<Integer> feedHashCodes;
private transient List<Feed> feeds;
- private final List<Keyword> keywords;
+ private List<Keyword> keywords;
private String title = "";
/**
@@ -76,6 +85,14 @@ public class Filter implements Storable, Comparable<Filter> {
setTitle(title);
}
+ private void writeObject(ObjectOutputStream stream) throws JSONException, IOException {
+ stream.writeObject(toJson().toString());
+ }
+
+ private void readObject(ObjectInputStream stream) throws JSONException, IOException, ClassNotFoundException {
+ fromJson(new JSONObject((String) stream.readObject()));
+ }
+
public List<Integer> getFeedHashCodes() {
return feedHashCodes;
}
@@ -165,11 +182,15 @@ public class Filter implements Storable, Comparable<Filter> {
* @param storageProvider
* @throws Exception
*/
- public synchronized void store(StorageProvider<Object,Filter> storageProvider) throws Exception {
+ public synchronized void store(FilterStorageProvider storageProvider) throws Exception {
if (storageKey == null) {
storageKey = storageProvider.uniqueKey();
}
- storageProvider.store(storageKey, this);
+ storageProvider.storeFilter(storageKey, this);
+ }
+
+ public synchronized void delete(FilterStorageProvider storageProvider) throws Exception {
+ storageProvider.removeFilter(storageKey);
}
/**
@@ -189,6 +210,29 @@ public class Filter implements Storable, Comparable<Filter> {
return title.compareTo(another.title);
}
+ @Override
+ public JSONObject toJson() throws JSONException {
+ JSONObject json = new JSONObject();
+ json.put("title", title);
+ json.put("feedHashCodes", JsonSerializer.numbersListToJson(feedHashCodes));
+ json.put("keywords", JsonSerializer.listToJson(keywords));
+ json.put("storageKey", storageKey.toString());
+ return json;
+ }
+
+ @Override
+ public void fromJson(JSONObject json) throws JSONException {
+ title = json.getString("title");
+ feedHashCodes = JsonSerializer.integersListFromJson(json.getJSONArray("feedHashCodes"));
+ JSONArray keywordsJson = json.getJSONArray("keywords");
+ keywords = new ArrayList<>();
+ for (int i = 0; i < keywordsJson.length(); i++) {
+ keywords.add(new Keyword(""));
+ }
+ JsonSerializer.listFromJson(keywordsJson, keywords);
+ storageKey = json.getString("storageKey");
+ }
+
private class FeedSorterStorer implements Runnable {
private final Object storageKey;
private final StorageProvider storageProvider;
@@ -210,4 +254,5 @@ public class Filter implements Storable, Comparable<Filter> {
}
}
}
+
}
diff --git a/app/src/main/java/org/rssin/rssin/Keyword.java b/app/src/main/java/org/rssin/rssin/Keyword.java
index 9b5adfb..532bd59 100644
--- a/app/src/main/java/org/rssin/rssin/Keyword.java
+++ b/app/src/main/java/org/rssin/rssin/Keyword.java
@@ -1,24 +1,39 @@
package org.rssin.rssin;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.rssin.serialization.Jsonable;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* Keyword holder
* @author Camil Staps
*/
-public class Keyword implements Serializable {
+public class Keyword implements Serializable, Jsonable {
- private static final long serialVersionUID = 0;
+ private static final long serialVersionUID = 1;
/**
* For now, Keywords only have a single String keyword. Later, more options may be added
*/
- private final String keyword;
+ private String keyword;
public Keyword(String keyword) {
this.keyword = keyword.trim();
}
+ private void writeObject(ObjectOutputStream stream) throws JSONException, IOException {
+ stream.writeObject(toJson().toString());
+ }
+
+ private void readObject(ObjectInputStream stream) throws JSONException, IOException, ClassNotFoundException {
+ fromJson(new JSONObject((String) stream.readObject()));
+ }
+
public String getKeyword() {
return keyword;
}
@@ -28,4 +43,15 @@ public class Keyword implements Serializable {
return keyword;
}
+ @Override
+ public JSONObject toJson() throws JSONException {
+ JSONObject json = new JSONObject();
+ json.put("keyword", keyword);
+ return json;
+ }
+
+ @Override
+ public void fromJson(JSONObject json) throws JSONException {
+ keyword = json.getString("keyword");
+ }
}
diff --git a/app/src/main/java/org/rssin/serialization/JsonSerializer.java b/app/src/main/java/org/rssin/serialization/JsonSerializer.java
new file mode 100644
index 0000000..ca060a5
--- /dev/null
+++ b/app/src/main/java/org/rssin/serialization/JsonSerializer.java
@@ -0,0 +1,59 @@
+package org.rssin.serialization;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Common tools for JSON serialization
+ * @author
+ */
+public class JsonSerializer {
+
+ /**
+ * Make a JSONArray from a List<? extends Jsonable>
+ * @param list the list to serialize
+ * @return the JSONArray
+ * @throws JSONException if this happens, it should be a problem in the Jsonable's toJson
+ */
+ public static JSONArray listToJson(List<? extends Jsonable> list) throws JSONException {
+ JSONArray json = new JSONArray();
+ for (Jsonable item : list) {
+ json.put(item.toJson());
+ }
+ return json;
+ }
+
+ public static JSONArray numbersListToJson(List<? extends Number> list) throws JSONException {
+ JSONArray json = new JSONArray();
+ for (Number item : list) {
+ json.put(item);
+ }
+ return json;
+ }
+
+ /**
+ * Read a JSONArray into a List<? extends Jsonable>
+ * Items are read until either the JSONArray is empty or the List is full.
+ *
+ * @param json the JSONArray
+ * @param list the list to read into
+ * @throws JSONException
+ */
+ public static void listFromJson(JSONArray json, List<? extends Jsonable> list) throws JSONException {
+ for (int i = 0; i < json.length() && i < list.size(); i++) {
+ list.get(i).fromJson(json.getJSONObject(i));
+ }
+ }
+
+ public static List<Integer> integersListFromJson(JSONArray json) throws JSONException {
+ List<Integer> list = new ArrayList<>();
+ for (int i = 0; i < json.length(); i++) {
+ list.add(json.getInt(i));
+ }
+ return list;
+ }
+
+}
diff --git a/app/src/main/java/org/rssin/serialization/Jsonable.java b/app/src/main/java/org/rssin/serialization/Jsonable.java
new file mode 100644
index 0000000..d97f2fd
--- /dev/null
+++ b/app/src/main/java/org/rssin/serialization/Jsonable.java
@@ -0,0 +1,15 @@
+package org.rssin.serialization;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Classes that can be stored with JSON
+ * @author Camil Staps
+ */
+public interface Jsonable {
+
+ JSONObject toJson() throws JSONException;
+ void fromJson(JSONObject json) throws JSONException;
+
+}
diff --git a/app/src/main/java/org/rssin/tools/SerializationTools.java b/app/src/main/java/org/rssin/serialization/SerializationTools.java
index 0886ded..7b06f55 100755
--- a/app/src/main/java/org/rssin/tools/SerializationTools.java
+++ b/app/src/main/java/org/rssin/serialization/SerializationTools.java
@@ -1,4 +1,4 @@
-package org.rssin.tools;
+package org.rssin.serialization;
import java.io.IOException;
import java.io.ObjectInputStream;
diff --git a/app/src/main/java/org/rssin/storage/FilterStorageProvider.java b/app/src/main/java/org/rssin/storage/FilterStorageProvider.java
index b1807d9..694bf70 100644
--- a/app/src/main/java/org/rssin/storage/FilterStorageProvider.java
+++ b/app/src/main/java/org/rssin/storage/FilterStorageProvider.java
@@ -17,6 +17,13 @@ public interface FilterStorageProvider<K> {
List<Filter> allFilters();
/**
+ * Save a Filter
+ * @param key
+ * @param filter
+ */
+ void storeFilter(K key, Filter filter) throws Exception;
+
+ /**
* Get the filter of a specific key
* @param key
* @return
@@ -29,4 +36,10 @@ public interface FilterStorageProvider<K> {
*/
void removeFilter(K key);
+ /**
+ * Get a new, unique, usable key
+ * @return
+ */
+ K uniqueKey();
+
}
diff --git a/app/src/main/java/org/rssin/storage/StorageProvider.java b/app/src/main/java/org/rssin/storage/StorageProvider.java
index 7e382c2..56c8a4c 100644
--- a/app/src/main/java/org/rssin/storage/StorageProvider.java
+++ b/app/src/main/java/org/rssin/storage/StorageProvider.java
@@ -21,6 +21,13 @@ public interface StorageProvider<K,E extends Storable> {
E fetch(K key, Class className) throws Exception;
/**
+ * Remove an element
+ * @param key
+ * @param className
+ */
+ void remove(K key, Class className) throws Exception;
+
+ /**
* Get a new, unique, usable key
* @return
*/