summaryrefslogtreecommitdiff
path: root/src/de/danoeh/antennapod
diff options
context:
space:
mode:
authorSimon Rutishauser <simon.rutishauser@web.de>2013-09-29 17:08:26 +0200
committerSimon Rutishauser <simon.rutishauser@web.de>2013-09-29 17:19:11 +0200
commit8fbd1ecf9ceec0523447346c1ae93e0cb612a96a (patch)
tree47d2ba041a28d44578ab7e72d2efe2fdbbaa751e /src/de/danoeh/antennapod
parent83bb0a608440c21ce61af68df0a8be0c387f1c0c (diff)
downloadAntennaPod-8fbd1ecf9ceec0523447346c1ae93e0cb612a96a.zip
this consolidates the code from pull request #253 (flattr queue and auto flattr) into a single commit, rebased onto the current development branch
Diffstat (limited to 'src/de/danoeh/antennapod')
-rw-r--r--src/de/danoeh/antennapod/activity/MediaplayerActivity.java16
-rw-r--r--src/de/danoeh/antennapod/activity/PreferenceActivity.java3
-rw-r--r--src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java220
-rw-r--r--src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java55
-rw-r--r--src/de/danoeh/antennapod/feed/Feed.java19
-rw-r--r--src/de/danoeh/antennapod/feed/FeedItem.java17
-rw-r--r--src/de/danoeh/antennapod/feed/FeedMedia.java38
-rw-r--r--src/de/danoeh/antennapod/preferences/UserPreferences.java10
-rw-r--r--src/de/danoeh/antennapod/storage/DBReader.java50
-rw-r--r--src/de/danoeh/antennapod/storage/DBTasks.java8
-rw-r--r--src/de/danoeh/antennapod/storage/DBWriter.java102
-rw-r--r--src/de/danoeh/antennapod/storage/PodDBAdapter.java39
-rw-r--r--src/de/danoeh/antennapod/util/flattr/FlattrStatus.java67
-rw-r--r--src/de/danoeh/antennapod/util/flattr/FlattrThing.java7
-rw-r--r--src/de/danoeh/antennapod/util/flattr/FlattrUtils.java59
-rw-r--r--src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java8
-rw-r--r--src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java11
17 files changed, 661 insertions, 68 deletions
diff --git a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 748a049a6..129134a47 100644
--- a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -21,14 +21,18 @@ import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.dialog.TimeDialog;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.util.Converter;
import de.danoeh.antennapod.util.ShareUtils;
import de.danoeh.antennapod.util.StorageUtils;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
import de.danoeh.antennapod.util.playback.MediaPlayerError;
import de.danoeh.antennapod.util.playback.Playable;
import de.danoeh.antennapod.util.playback.PlaybackController;
+import de.danoeh.antennapod.storage.DBWriter;
/**
* Provides general features which are both needed for playing audio and video
@@ -309,8 +313,16 @@ public abstract class MediaplayerActivity extends ActionBarActivity
startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
case R.id.support_item:
- new FlattrClickWorker(this, media.getPaymentLink())
- .executeAsync();
+ try {
+ FeedItem feedItem = ((FeedMedia) media).getItem();
+ feedItem.getFlattrStatus().setFlattrQueue();
+
+ DBWriter.setFeedItem(this, feedItem);
+ new FlattrClickWorker(this).executeAsync();
+ }
+ catch (ClassCastException e) {
+ Log.d(TAG, "Could not flattr item - most likely external media: " + e.toString());
+ }
break;
case R.id.share_link_item:
ShareUtils.shareLink(this, media.getWebsiteLink());
diff --git a/src/de/danoeh/antennapod/activity/PreferenceActivity.java b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
index e6fcf5306..beaade2b0 100644
--- a/src/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -28,6 +28,7 @@ import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
import de.danoeh.antennapod.preferences.GpodnetPreferences;
import de.danoeh.antennapod.preferences.UserPreferences;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
import de.danoeh.antennapod.util.flattr.FlattrUtils;
import java.io.File;
@@ -44,6 +45,7 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
private static final String PREF_FLATTR_THIS_APP = "prefFlattrThisApp";
private static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate";
private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
+ private static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
private static final String PREF_OPML_EXPORT = "prefOpmlExport";
private static final String PREF_ABOUT = "prefAbout";
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
@@ -297,6 +299,7 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
findPreference(PREF_FLATTR_AUTH).setEnabled(!hasFlattrToken);
findPreference(PREF_FLATTR_REVOKE).setEnabled(hasFlattrToken);
+ findPreference(PREF_AUTO_FLATTR).setEnabled(hasFlattrToken);
findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
.setEnabled(UserPreferences.isEnableAutodownload());
diff --git a/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java b/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java
index 975aa5efe..f97223ff5 100644
--- a/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java
+++ b/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java
@@ -1,107 +1,245 @@
package de.danoeh.antennapod.asynctask;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
import org.shredzone.flattr4j.exception.FlattrException;
+import org.shredzone.flattr4j.model.Flattr;
import android.annotation.SuppressLint;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.AsyncTask;
+import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.FeedItemlistActivity;
+import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.util.flattr.FlattrThing;
import de.danoeh.antennapod.util.flattr.FlattrUtils;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DBWriter;
/** Performs a click action in a background thread. */
-public class FlattrClickWorker extends AsyncTask<Void, Void, Void> {
+public class FlattrClickWorker extends AsyncTask<Void, String, Void> {
protected static final String TAG = "FlattrClickWorker";
protected Context context;
- protected String url;
+
+ private final int NOTIFICATION_ID = 4;
+
protected String errorMsg;
protected int exitCode;
+ protected ArrayList<String> flattrd;
+ protected ArrayList<String> flattr_failed;
+
+ protected NotificationCompat.Builder notificationBuilder;
+ protected NotificationManager notificationManager;
+
protected ProgressDialog progDialog;
- protected final static int SUCCESS = 0;
+ protected final static int EXIT_DEFAULT = 0;
protected final static int NO_TOKEN = 1;
- protected final static int FLATTR_ERROR = 2;
+ protected final static int ENQUEUED = 2;
+ protected final static int NO_THINGS = 3;
+
+ private boolean enqueue_only = false;
- public FlattrClickWorker(Context context, String url) {
+ public FlattrClickWorker(Context context, boolean enqueue_only) {
+ this(context);
+ this.enqueue_only = enqueue_only;
+ }
+
+ public FlattrClickWorker(Context context) {
super();
this.context = context;
- this.url = url;
- exitCode = SUCCESS;
+ exitCode = EXIT_DEFAULT;
+
+ flattrd = new ArrayList<String>();
+ flattr_failed = new ArrayList<String>();
+
errorMsg = "";
}
+ /* only used in PreferencesActivity for flattring antennapod itself,
+ * can't really enqueue this thing
+ */
+ public FlattrClickWorker(Context context, String url) {
+ Log.e(TAG, "Not implemented yet");
+ }
+
protected void onNoAccessToken() {
Log.w(TAG, "No access token was available");
- if (url.equals(FlattrUtils.APP_URL)) {
- FlattrUtils.showNoTokenDialog(context, FlattrUtils.APP_LINK);
- } else {
- FlattrUtils.showNoTokenDialog(context, url);
- }
+ FlattrUtils.showNoTokenDialog(context, "");
}
protected void onFlattrError() {
FlattrUtils.showErrorDialog(context, errorMsg);
}
-
- protected void onSuccess() {
- Toast toast = Toast.makeText(context.getApplicationContext(),
- R.string.flattr_click_success, Toast.LENGTH_LONG);
- toast.show();
+
+ protected void onFlattred() {
+ String notificationTitle = context.getString(R.string.flattrd_label);
+ String notificationText = "", notificationSubText = "";
+
+ // text for successfully flattred items
+ if (flattrd.size() == 1)
+ notificationText = String.format(context.getString(R.string.flattr_click_success));
+ else if (flattrd.size() > 1) // flattred pending items from queue
+ notificationText = String.format(context.getString(R.string.flattr_click_success_count, flattrd.size()));
+
+ if (flattrd.size() > 0) {
+ String acc = "";
+ for (String s: flattrd)
+ acc += s + ", ";
+ acc = acc.substring(0, acc.length()-2);
+
+ notificationSubText = String.format(context.getString(R.string.flattr_click_success_queue), acc);
+ }
+
+ // add text for failures
+ if (flattr_failed.size() > 0) {
+ notificationTitle = context.getString(R.string.flattrd_failed_label);
+ notificationText = String.format(context.getString(R.string.flattr_click_failure_count), flattr_failed.size())
+ + " " + notificationText;
+
+ String acc = "";
+ for (String s: flattr_failed)
+ acc += s + ", ";
+ acc = acc.substring(0, acc.length()-2);
+
+ notificationSubText = String.format(context.getString(R.string.flattr_click_failure), acc)
+ + " " + notificationSubText;
+ }
+
+ notificationBuilder = new NotificationCompat.Builder(context) // need new notificationBuilder and cancel/renotify to get rid of progress bar
+ .setContentTitle(notificationTitle)
+ .setContentText(notificationText)
+ .setSubText(notificationSubText)
+ .setTicker(notificationTitle)
+ .setSmallIcon(R.drawable.stat_notify_sync)
+ .setOngoing(false);
+ notificationManager.cancel(NOTIFICATION_ID);
+ notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ }
+
+ protected void onEnqueue() {
+ Toast.makeText(context.getApplicationContext(),
+ R.string.flattr_click_enqueued,
+ Toast.LENGTH_LONG)
+ .show();
}
- protected void onSetupProgDialog() {
- progDialog = new ProgressDialog(context);
- progDialog.setMessage(context.getString(R.string.flattring_label));
- progDialog.setIndeterminate(true);
- progDialog.setCancelable(false);
- progDialog.show();
+ protected void onSetupNotification() {
+ notificationBuilder = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.flattring_label))
+ .setAutoCancel(true)
+ .setSmallIcon(R.drawable.stat_notify_sync)
+ .setProgress(0, 0, true)
+ .setOngoing(true);
+
+ notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
@Override
protected void onPostExecute(Void result) {
if (AppConfig.DEBUG) Log.d(TAG, "Exit code was " + exitCode);
- if (progDialog != null) {
- progDialog.dismiss();
- }
+
switch (exitCode) {
case NO_TOKEN:
+ notificationManager.cancel(NOTIFICATION_ID);
onNoAccessToken();
break;
- case FLATTR_ERROR:
- onFlattrError();
+ case ENQUEUED:
+ onEnqueue();
+ break;
+ case EXIT_DEFAULT:
+ onFlattred();
break;
- case SUCCESS:
- onSuccess();
+ case NO_THINGS: // FlattrClickWorker called automatically somewhere to empty flattr queue
+ notificationManager.cancel(NOTIFICATION_ID);
break;
}
}
@Override
protected void onPreExecute() {
- onSetupProgDialog();
+ onSetupNotification();
}
+ private static boolean haveInternetAccess(Context context) {
+ ConnectivityManager cm =
+ (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ NetworkInfo networkInfo = cm.getActiveNetworkInfo();
+ return (networkInfo != null && networkInfo.isConnectedOrConnecting());
+ }
+
@Override
protected Void doInBackground(Void... params) {
if (AppConfig.DEBUG) Log.d(TAG, "Starting background work");
- if (FlattrUtils.hasToken()) {
- try {
- FlattrUtils.clickUrl(context, url);
- } catch (FlattrException e) {
- e.printStackTrace();
- exitCode = FLATTR_ERROR;
- errorMsg = e.getMessage();
- }
- } else {
+
+ exitCode = EXIT_DEFAULT;
+
+ if (!FlattrUtils.hasToken()) {
exitCode = NO_TOKEN;
}
+ else if (DBReader.getFlattrQueueEmpty(context)) {
+ exitCode = NO_THINGS;
+ }
+ else if (!haveInternetAccess(context) || enqueue_only) {
+ exitCode = ENQUEUED;
+ }
+ else {
+ List<FlattrThing> flattrList = DBReader.getFlattrQueue(context);
+ Log.d(TAG, "flattrQueue processing list with " + flattrList.size() + " items.");
+
+ flattrd.ensureCapacity(flattrList.size());
+
+ for (FlattrThing thing: flattrList) {
+ try {
+ Log.d(TAG, "flattrQueue processing " + thing.getTitle() + " " + thing.getPaymentLink());
+ publishProgress(String.format(context.getString(R.string.flattring_thing), thing.getTitle()));
+
+ thing.getFlattrStatus().setUnflattred(); // pop from queue to prevent unflattrable things from getting stuck in flattr queue infinitely
+
+ FlattrUtils.clickUrl(context, thing.getPaymentLink());
+ flattrd.add(thing.getTitle());
+
+ thing.getFlattrStatus().setFlattred();
+ }
+ catch (FlattrException e) {
+ Log.d(TAG, "flattrQueue processing exception at item " + thing.getTitle() + " " + e.getMessage());
+ flattr_failed.ensureCapacity(flattrList.size());
+ flattr_failed.add(thing.getTitle());
+ }
+ Log.d(TAG, "flattrQueue processing - going to write thing back to db with flattr_status " + Long.toString(thing.getFlattrStatus().toLong()));
+ DBWriter.setFlattredStatus(context, thing);
+ }
+
+ }
+
return null;
}
-
+
+ @Override
+ protected void onProgressUpdate(String... names) {
+ notificationBuilder.setContentText(names[0]);
+ notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ }
+
@SuppressLint("NewApi")
public void executeAsync() {
FlattrUtils.hasToken();
diff --git a/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java b/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java
new file mode 100644
index 000000000..00e91c399
--- /dev/null
+++ b/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java
@@ -0,0 +1,55 @@
+package de.danoeh.antennapod.asynctask;
+
+import java.util.List;
+
+import org.shredzone.flattr4j.exception.FlattrException;
+import org.shredzone.flattr4j.model.Flattr;
+
+import android.util.Log;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.AsyncTask;
+import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.util.flattr.FlattrUtils;
+import de.danoeh.antennapod.storage.DBWriter;
+
+/** Fetch list of flattred things and flattr status in database in a background thread. */
+
+public class FlattrStatusFetcher extends AsyncTask<Void, Void, Void> {
+ protected static final String TAG = "FlattrStatusFetcher";
+ protected Context context;
+
+ public FlattrStatusFetcher(Context context) {
+ super();
+ this.context = context;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ if (AppConfig.DEBUG) Log.d(TAG, "Starting background work: Retrieving Flattr status");
+
+ Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
+
+ try {
+ List<Flattr> flattredThings = FlattrUtils.retrieveFlattredThings();
+ DBWriter.setFlattredStatus(context, flattredThings);
+ }
+ catch (FlattrException e) {
+ Log.d(TAG, "flattrQueue exception retrieving list with flattred items " + e.getMessage());
+ }
+
+ if (AppConfig.DEBUG) Log.d(TAG, "Finished background work: Retrieved Flattr status");
+
+ return null;
+ }
+
+ @SuppressLint("NewApi")
+ public void executeAsync() {
+ FlattrUtils.hasToken();
+ if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+ executeOnExecutor(THREAD_POOL_EXECUTOR);
+ } else {
+ execute();
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/feed/Feed.java b/src/de/danoeh/antennapod/feed/Feed.java
index 032930f83..6df7bacd8 100644
--- a/src/de/danoeh/antennapod/feed/Feed.java
+++ b/src/de/danoeh/antennapod/feed/Feed.java
@@ -7,13 +7,15 @@ import java.util.List;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.util.EpisodeFilter;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import de.danoeh.antennapod.util.flattr.FlattrThing;
/**
* Data Object for a whole feed
*
* @author daniel
*/
-public class Feed extends FeedFile {
+public class Feed extends FeedFile implements FlattrThing {
public static final int FEEDFILETYPE_FEED = 0;
public static final String TYPE_RSS2 = "rss";
public static final String TYPE_RSS091 = "rss";
@@ -40,6 +42,7 @@ public class Feed extends FeedFile {
* Date of last refresh.
*/
private Date lastUpdate;
+ private FlattrStatus flattrStatus;
private String paymentLink;
/**
* Feed type, for example RSS 2 or Atom
@@ -51,7 +54,7 @@ public class Feed extends FeedFile {
*/
public Feed(long id, Date lastUpdate, String title, String link, String description, String paymentLink,
String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
- String downloadUrl, boolean downloaded) {
+ String downloadUrl, boolean downloaded, FlattrStatus status) {
super(fileUrl, downloadUrl, downloaded);
this.id = id;
this.title = title;
@@ -68,6 +71,7 @@ public class Feed extends FeedFile {
this.type = type;
this.feedIdentifier = feedIdentifier;
this.image = image;
+ this.flattrStatus = status;
items = new ArrayList<FeedItem>();
}
@@ -79,6 +83,7 @@ public class Feed extends FeedFile {
super();
items = new ArrayList<FeedItem>();
lastUpdate = new Date();
+ this.flattrStatus = new FlattrStatus();
}
/**
@@ -88,6 +93,7 @@ public class Feed extends FeedFile {
public Feed(String url, Date lastUpdate) {
super(null, url, false);
this.lastUpdate = (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
+ this.flattrStatus = new FlattrStatus();
}
/**
@@ -97,6 +103,7 @@ public class Feed extends FeedFile {
public Feed(String url, Date lastUpdate, String title) {
this(url, lastUpdate);
this.title = title;
+ this.flattrStatus = new FlattrStatus();
}
/**
@@ -334,6 +341,14 @@ public class Feed extends FeedFile {
this.feedIdentifier = feedIdentifier;
}
+ public void setFlattrStatus(FlattrStatus status) {
+ this.flattrStatus = status;
+ }
+
+ public FlattrStatus getFlattrStatus() {
+ return flattrStatus;
+ }
+
public String getPaymentLink() {
return paymentLink;
}
diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java
index a80460ece..37388fe44 100644
--- a/src/de/danoeh/antennapod/feed/FeedItem.java
+++ b/src/de/danoeh/antennapod/feed/FeedItem.java
@@ -10,6 +10,8 @@ import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.util.ShownotesProvider;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import de.danoeh.antennapod.util.flattr.FlattrThing;
/**
* Data Object for a XML message
@@ -17,7 +19,7 @@ import de.danoeh.antennapod.util.ShownotesProvider;
* @author daniel
*/
public class FeedItem extends FeedComponent implements
- ImageLoader.ImageWorkerTaskResource, ShownotesProvider {
+ ImageLoader.ImageWorkerTaskResource, ShownotesProvider, FlattrThing {
/**
* The id/guid that can be found in the rss/atom feed. Might not be set.
@@ -42,10 +44,12 @@ public class FeedItem extends FeedComponent implements
private boolean read;
private String paymentLink;
+ private FlattrStatus flattrStatus;
private List<Chapter> chapters;
public FeedItem() {
this.read = true;
+ this.flattrStatus = new FlattrStatus();
}
/**
@@ -59,6 +63,7 @@ public class FeedItem extends FeedComponent implements
this.pubDate = (pubDate != null) ? (Date) pubDate.clone() : null;
this.read = read;
this.feed = feed;
+ this.flattrStatus = new FlattrStatus();
}
public void updateFromOther(FeedItem other) {
@@ -195,7 +200,15 @@ public class FeedItem extends FeedComponent implements
this.contentEncoded = contentEncoded;
}
- public String getPaymentLink() {
+ public void setFlattrStatus(FlattrStatus status) {
+ this.flattrStatus = status;
+ }
+
+ public FlattrStatus getFlattrStatus() {
+ return flattrStatus;
+ }
+
+ public String getPaymentLink() {
return paymentLink;
}
diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java
index 492867983..be3af967f 100644
--- a/src/de/danoeh/antennapod/feed/FeedMedia.java
+++ b/src/de/danoeh/antennapod/feed/FeedMedia.java
@@ -10,14 +10,19 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import de.danoeh.antennapod.PodcastApp;
+import de.danoeh.antennapod.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.util.ChapterUtils;
import de.danoeh.antennapod.util.playback.Playable;
public class FeedMedia extends FeedFile implements Playable {
+ private static final String TAG = "FeedMedia";
public static final int FEEDFILETYPE_FEEDMEDIA = 2;
public static final int PLAYABLE_TYPE_FEEDMEDIA = 1;
@@ -27,6 +32,7 @@ public class FeedMedia extends FeedFile implements Playable {
private int duration;
private int position; // Current position in file
+ private int played_duration; // How many ms of this file have been played (for autoflattring)
private long size; // File size in Byte
private String mime_type;
private volatile FeedItem item;
@@ -45,12 +51,13 @@ public class FeedMedia extends FeedFile implements Playable {
public FeedMedia(long id, FeedItem item, int duration, int position,
long size, String mime_type, String file_url, String download_url,
- boolean downloaded, Date playbackCompletionDate) {
+ boolean downloaded, Date playbackCompletionDate, int played_duration) {
super(file_url, download_url, downloaded);
this.id = id;
this.item = item;
this.duration = duration;
this.position = position;
+ this.played_duration = played_duration;
this.size = size;
this.mime_type = mime_type;
this.playbackCompletionDate = playbackCompletionDate == null
@@ -137,12 +144,20 @@ public class FeedMedia extends FeedFile implements Playable {
this.duration = duration;
}
- public int getPosition() {
+ public int getPlayedDuration() {
+ return played_duration;
+ }
+
+ public int getPosition() {
return position;
}
public void setPosition(int position) {
- this.position = position;
+ final int WAITING_INTERVAL = 5000;
+ if (position > this.position)
+ played_duration += Math.min(position - this.position, 1.1*WAITING_INTERVAL);
+
+ this.position = position;
}
public long getSize() {
@@ -215,6 +230,7 @@ public class FeedMedia extends FeedFile implements Playable {
dest.writeString(download_url);
dest.writeByte((byte) ((downloaded) ? 1 : 0));
dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0);
+ dest.writeInt(played_duration);
}
@Override
@@ -313,8 +329,18 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
- position = newPosition;
- DBWriter.setFeedMediaPlaybackInformation(PodcastApp.getInstance(), this);
+ setPosition(newPosition);
+
+ // Auto flattr
+ if (UserPreferences.isAutoFlattr() && item.getPaymentLink() != null && item.getFlattrStatus().getUnflattred() && (played_duration > 0.8*duration)) {
+ Log.d(TAG, "saveCurrentPosition: performing auto flattr since played duration " + Integer.toString(played_duration) + " is 80% of file duration " + Integer.toString(duration));
+ item.getFlattrStatus().setFlattrQueue();
+
+ DBWriter.setFeedItem(PodcastApp.getInstance(), item);
+ new FlattrClickWorker(PodcastApp.getInstance(), true).executeAsync();
+ }
+
+ DBWriter.setFeedMediaPlaybackInformation(PodcastApp.getInstance(), this);
}
@Override
@@ -358,7 +384,7 @@ public class FeedMedia extends FeedFile implements Playable {
final long id = in.readLong();
final long itemID = in.readLong();
FeedMedia result = new FeedMedia(id, null, in.readInt(), in.readInt(), in.readLong(), in.readString(), in.readString(),
- in.readString(), in.readByte() != 0, new Date(in.readLong()));
+ in.readString(), in.readByte() != 0, new Date(in.readLong()), in.readInt());
result.itemID = itemID;
return result;
}
diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java
index d15f5ba53..538c6238e 100644
--- a/src/de/danoeh/antennapod/preferences/UserPreferences.java
+++ b/src/de/danoeh/antennapod/preferences/UserPreferences.java
@@ -40,6 +40,7 @@ public class UserPreferences implements
public static final String PREF_MOBILE_UPDATE = "prefMobileUpdate";
public static final String PREF_DISPLAY_ONLY_EPISODES = "prefDisplayOnlyEpisodes";
public static final String PREF_AUTO_DELETE = "prefAutoDelete";
+ public static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
public static final String PREF_THEME = "prefTheme";
public static final String PREF_DATA_FOLDER = "prefDataFolder";
public static final String PREF_ENABLE_AUTODL = "prefEnableAutoDl";
@@ -62,6 +63,7 @@ public class UserPreferences implements
private boolean allowMobileUpdate;
private boolean displayOnlyEpisodes;
private boolean autoDelete;
+ private boolean autoFlattr;
private int theme;
private boolean enableAutodownload;
private boolean enableAutodownloadWifiFilter;
@@ -110,6 +112,7 @@ public class UserPreferences implements
allowMobileUpdate = sp.getBoolean(PREF_MOBILE_UPDATE, false);
displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES, false);
autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false);
+ autoFlattr = sp.getBoolean(PREF_AUTO_FLATTR, false);
theme = readThemeValue(sp.getString(PREF_THEME, "0"));
enableAutodownloadWifiFilter = sp.getBoolean(
PREF_ENABLE_AUTODL_WIFI_FILTER, false);
@@ -220,6 +223,11 @@ public class UserPreferences implements
instanceAvailable();
return instance.autoDelete;
}
+
+ public static boolean isAutoFlattr() {
+ instanceAvailable();
+ return instance.autoFlattr;
+ }
public static int getTheme() {
instanceAvailable();
@@ -288,6 +296,8 @@ public class UserPreferences implements
} else if (key.equals(PREF_AUTO_DELETE)) {
autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false);
+ } else if (key.equals(PREF_AUTO_FLATTR)) {
+ autoFlattr = sp.getBoolean(PREF_AUTO_FLATTR, false);
} else if (key.equals(PREF_DISPLAY_ONLY_EPISODES)) {
displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES,
false);
diff --git a/src/de/danoeh/antennapod/storage/DBReader.java b/src/de/danoeh/antennapod/storage/DBReader.java
index a5a4c8cd4..404952039 100644
--- a/src/de/danoeh/antennapod/storage/DBReader.java
+++ b/src/de/danoeh/antennapod/storage/DBReader.java
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.LinkedList;
import android.content.Context;
import android.database.Cursor;
@@ -22,6 +23,8 @@ import de.danoeh.antennapod.service.download.*;
import de.danoeh.antennapod.util.DownloadError;
import de.danoeh.antennapod.util.comparator.DownloadStatusComparator;
import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
+import de.danoeh.antennapod.util.flattr.FlattrThing;
/**
* Provides methods for reading data from the AntennaPod database.
@@ -216,6 +219,8 @@ public final class DBReader {
.getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0));
item.setItemIdentifier(itemlistCursor
.getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER));
+ item.setFlattrStatus(new FlattrStatus(itemlistCursor
+ .getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS)));
// extract chapters
boolean hasSimpleChapters = itemlistCursor
@@ -307,7 +312,8 @@ public final class DBReader {
cursor.getString(PodDBAdapter.KEY_FILE_URL_INDEX),
cursor.getString(PodDBAdapter.KEY_DOWNLOAD_URL_INDEX),
cursor.getInt(PodDBAdapter.KEY_DOWNLOADED_INDEX) > 0,
- playbackCompletionDate);
+ playbackCompletionDate,
+ cursor.getInt(PodDBAdapter.KEY_PLAYED_DURATION_INDEX));
}
private static Feed extractFeedFromCursorRow(PodDBAdapter adapter,
@@ -335,7 +341,9 @@ public final class DBReader {
image,
cursor.getString(PodDBAdapter.KEY_FILE_URL_INDEX),
cursor.getString(PodDBAdapter.KEY_DOWNLOAD_URL_INDEX),
- cursor.getInt(PodDBAdapter.KEY_DOWNLOADED_INDEX) > 0);
+ cursor.getInt(PodDBAdapter.KEY_DOWNLOADED_INDEX) > 0,
+ new FlattrStatus(cursor.getLong(PodDBAdapter.KEY_FEED_FLATTR_STATUS_INDEX))
+ );
if (image != null) {
image.setFeed(feed);
@@ -775,4 +783,42 @@ public final class DBReader {
return media;
}
+
+
+ public static List<FlattrThing> getFlattrQueue(Context context) {
+ List<Feed> feeds = getFeedList(context);
+ List<FlattrThing> l = new LinkedList<FlattrThing>();
+
+ for (Feed feed : feeds) {
+ if (feed.getFlattrStatus().getFlattrQueue())
+ l.add(feed);
+
+ for (FeedItem item : getFeedItemList(context, feed))
+ if (item.getFlattrStatus().getFlattrQueue())
+ l.add(item);
+ }
+
+ Log.d(TAG, "Returning flattrQueueIterator for queue with " + l.size() + " items.");
+ return l;
+ }
+
+
+ public static boolean getFlattrQueueEmpty(Context context) {
+ List<Feed> feeds = getFeedList(context);
+
+ for (Feed feed : feeds) {
+ if (feed.getFlattrStatus().getFlattrQueue())
+ return false;
+ }
+
+ for (Feed feed : feeds) {
+ for (FeedItem item : getFeedItemList(context, feed))
+ if (item.getFlattrStatus().getFlattrQueue())
+ return false;
+ }
+
+ Log.d(TAG, "getFlattrQueueEmpty() = true");
+
+ return true;
+ }
}
diff --git a/src/de/danoeh/antennapod/storage/DBTasks.java b/src/de/danoeh/antennapod/storage/DBTasks.java
index b9a1fd002..efc40a7bb 100644
--- a/src/de/danoeh/antennapod/storage/DBTasks.java
+++ b/src/de/danoeh/antennapod/storage/DBTasks.java
@@ -16,6 +16,8 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.util.Log;
+import de.danoeh.antennapod.asynctask.FlattrClickWorker;
+import de.danoeh.antennapod.asynctask.FlattrStatusFetcher;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.Feed;
@@ -149,6 +151,12 @@ public final class DBTasks {
GpodnetSyncService.sendSyncIntent(context);
}
}.start();
+
+ if (AppConfig.DEBUG) Log.d(TAG, "Flattring all pending things.");
+ new FlattrClickWorker(context).executeAsync(); // flattr pending things
+
+ if (AppConfig.DEBUG) Log.d(TAG, "Fetching flattr status.");
+ new FlattrStatusFetcher(context).executeAsync();
} else {
if (AppConfig.DEBUG)
Log.d(TAG,
diff --git a/src/de/danoeh/antennapod/storage/DBWriter.java b/src/de/danoeh/antennapod/storage/DBWriter.java
index 9eb0ab643..cdebd5436 100644
--- a/src/de/danoeh/antennapod/storage/DBWriter.java
+++ b/src/de/danoeh/antennapod/storage/DBWriter.java
@@ -2,20 +2,26 @@ package de.danoeh.antennapod.storage;
import java.io.File;
import java.util.Date;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
+import org.shredzone.flattr4j.model.Flattr;
+
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.preference.PreferenceManager;
import android.util.Log;
+import android.net.Uri;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.feed.*;
import de.danoeh.antennapod.preferences.GpodnetPreferences;
@@ -24,6 +30,7 @@ import de.danoeh.antennapod.service.GpodnetSyncService;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.service.download.DownloadStatus;
import de.danoeh.antennapod.util.QueueAccess;
+import de.danoeh.antennapod.util.flattr.*;
/**
* Provides methods for writing data to AntennaPod's database.
@@ -825,4 +832,99 @@ public class DBWriter {
}
return false;
}
+
+ private static String normalizeURI(String uri) {
+ String normalizedURI = null;
+ if (uri != null) {
+ try {
+ normalizedURI = (new URI(uri)).normalize().toString();
+ if (! normalizedURI.endsWith("/"))
+ normalizedURI = normalizedURI + "/";
+ }
+ catch (URISyntaxException e) {
+ }
+ }
+ return normalizedURI;
+ }
+
+
+ // Set flattr status of the passed thing (either a FeedItem or a Feed)
+ public static void setFlattredStatus(Context context, FlattrThing thing) {
+ // must propagate this to back db
+ if (thing instanceof FeedItem)
+ DBWriter.setFeedItem(context, (FeedItem) thing);
+ else if (thing instanceof Feed)
+ DBWriter.setCompleteFeed(context, (Feed) thing);
+ else
+ Log.e(TAG, "flattrQueue processing - thing is neither FeedItem nor Feed");
+ }
+
+ /*
+ * Set flattr status of the feeds/feeditems in flattrList to flattred at the given timestamp,
+ * where the information has been retrieved from the flattr API
+ */
+ public static void setFlattredStatus(Context context, List<Flattr> flattrList) {
+ class FlattrLinkTime {
+ public String paymentLink;
+ public long time;
+
+ FlattrLinkTime(String paymentLink, long time) {
+ this.paymentLink = paymentLink;
+ this.time = time;
+ }
+ }
+
+ // build list with flattred things having normalized URLs
+ ArrayList<FlattrLinkTime> flattrLinkTime = new ArrayList<FlattrLinkTime>(flattrList.size());
+ for (Flattr flattr: flattrList) {
+ flattrLinkTime.add(new FlattrLinkTime(normalizeURI(flattr.getThing().getUrl()), flattr.getCreated().getTime()));
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "FlattredUrl: " + flattr.getThing().getUrl());
+ }
+
+
+ String paymentLink;
+ List<Feed> feeds = DBReader.getFeedList(context);
+ for (Feed feed: feeds) {
+ // check if the feed has been flattred
+ paymentLink = feed.getPaymentLink();
+ if (paymentLink != null) {
+ String feedThingUrl = normalizeURI(Uri.parse(paymentLink).getQueryParameter("url"));
+
+ feed.getFlattrStatus().setUnflattred(); // reset our offline status tracking
+
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Feed: Trying to match " + feedThingUrl);
+ for (FlattrLinkTime flattr: flattrLinkTime) {
+ if (flattr.paymentLink.equals(feedThingUrl)) {
+ feed.setFlattrStatus(new FlattrStatus(flattr.time));
+ setCompleteFeed(context, feed);
+ break;
+ }
+ }
+ }
+
+ // check if any of the feeditems have been flattred
+ for (FeedItem item: DBReader.getFeedItemList(context, feed)) {
+ paymentLink = item.getPaymentLink();
+
+ if (paymentLink != null) {
+ String feedItemThingUrl = normalizeURI(Uri.parse(paymentLink).getQueryParameter("url"));
+
+ item.getFlattrStatus().setUnflattred(); // reset our offline status tracking
+
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "FeedItem: Trying to match " + feedItemThingUrl);
+ for (FlattrLinkTime flattr: flattrLinkTime) {
+ if (flattr.paymentLink.equals(feedItemThingUrl)) {
+ item.setFlattrStatus(new FlattrStatus(flattr.time));
+ setFeedItem(context, item);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
}
diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
index e22fe56c9..71c0f787e 100644
--- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java
+++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.storage;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
import android.content.ContentValues;
@@ -20,6 +21,7 @@ import de.danoeh.antennapod.feed.FeedImage;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.service.download.DownloadStatus;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
// TODO Remove media column from feeditem table
@@ -28,7 +30,7 @@ import de.danoeh.antennapod.service.download.DownloadStatus;
*/
public class PodDBAdapter {
private static final String TAG = "PodDBAdapter";
- private static final int DATABASE_VERSION = 9;
+ private static final int DATABASE_VERSION = 10;
public static final String DATABASE_NAME = "Antennapod.db";
/**
@@ -58,6 +60,7 @@ public class PodDBAdapter {
public static final int KEY_IMAGE_INDEX = 11;
public static final int KEY_TYPE_INDEX = 12;
public static final int KEY_FEED_IDENTIFIER_INDEX = 13;
+ public static final int KEY_FEED_FLATTR_STATUS_INDEX = 14;
// ----------- FeedItem indices
public static final int KEY_CONTENT_ENCODED_INDEX = 2;
public static final int KEY_PUBDATE_INDEX = 3;
@@ -66,6 +69,7 @@ public class PodDBAdapter {
public static final int KEY_FEED_INDEX = 9;
public static final int KEY_HAS_SIMPLECHAPTERS_INDEX = 10;
public static final int KEY_ITEM_IDENTIFIER_INDEX = 11;
+ public static final int KEY_ITEM_FLATTR_STATUS_INDEX = 12;
// ---------- FeedMedia indices
public static final int KEY_DURATION_INDEX = 1;
public static final int KEY_POSITION_INDEX = 5;
@@ -73,6 +77,7 @@ public class PodDBAdapter {
public static final int KEY_MIME_TYPE_INDEX = 7;
public static final int KEY_PLAYBACK_COMPLETION_DATE_INDEX = 8;
public static final int KEY_MEDIA_FEEDITEM_INDEX = 9;
+ public static final int KEY_PLAYED_DURATION_INDEX = 10;
// --------- Download log indices
public static final int KEY_FEEDFILE_INDEX = 1;
public static final int KEY_FEEDFILETYPE_INDEX = 2;
@@ -123,11 +128,13 @@ public class PodDBAdapter {
public static final String KEY_HAS_CHAPTERS = "has_simple_chapters";
public static final String KEY_TYPE = "type";
public static final String KEY_ITEM_IDENTIFIER = "item_identifier";
+ public static final String KEY_FLATTR_STATUS = "flattr_status";
public static final String KEY_FEED_IDENTIFIER = "feed_identifier";
public static final String KEY_REASON_DETAILED = "reason_detailed";
public static final String KEY_DOWNLOADSTATUS_TITLE = "title";
public static final String KEY_CHAPTER_TYPE = "type";
public static final String KEY_PLAYBACK_COMPLETION_DATE = "playback_completion_date";
+ public static final String KEY_PLAYED_DURATION = "played_duration";
// Table names
public static final String TABLE_NAME_FEEDS = "Feeds";
@@ -149,8 +156,8 @@ public class PodDBAdapter {
+ KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
+ KEY_LASTUPDATE + " TEXT," + KEY_LANGUAGE + " TEXT," + KEY_AUTHOR
+ " TEXT," + KEY_IMAGE + " INTEGER," + KEY_TYPE + " TEXT,"
- + KEY_FEED_IDENTIFIER + " TEXT)";
- ;
+ + KEY_FEED_IDENTIFIER + " TEXT,"
+ + KEY_FLATTR_STATUS + " LONG)";
private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
+ TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
@@ -158,7 +165,8 @@ public class PodDBAdapter {
+ " INTEGER," + KEY_READ + " INTEGER," + KEY_LINK + " TEXT,"
+ KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
+ KEY_MEDIA + " INTEGER," + KEY_FEED + " INTEGER,"
- + KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT)";
+ + KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT,"
+ + KEY_FLATTR_STATUS + " LONG)";
private static final String CREATE_TABLE_FEED_IMAGES = "CREATE TABLE "
+ TABLE_NAME_FEED_IMAGES + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
@@ -171,7 +179,8 @@ public class PodDBAdapter {
+ " TEXT," + KEY_DOWNLOADED + " INTEGER," + KEY_POSITION
+ " INTEGER," + KEY_SIZE + " INTEGER," + KEY_MIME_TYPE + " TEXT,"
+ KEY_PLAYBACK_COMPLETION_DATE + " INTEGER,"
- + KEY_FEEDITEM + " INTEGER)";
+ + KEY_FEEDITEM + " INTEGER,"
+ + KEY_PLAYED_DURATION + " INTEGER)";
private static final String CREATE_TABLE_DOWNLOAD_LOG = "CREATE TABLE "
+ TABLE_NAME_DOWNLOAD_LOG + " (" + TABLE_PRIMARY_KEY + KEY_FEEDFILE
@@ -206,7 +215,8 @@ public class PodDBAdapter {
TABLE_NAME_FEED_ITEMS + "." + KEY_PAYMENT_LINK, KEY_MEDIA,
TABLE_NAME_FEED_ITEMS + "." + KEY_FEED,
TABLE_NAME_FEED_ITEMS + "." + KEY_HAS_CHAPTERS,
- TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER};
+ TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER,
+ TABLE_NAME_FEED_ITEMS + "." + KEY_FLATTR_STATUS};
/**
* Contains SEL_FI_SMALL as comma-separated list. Useful for raw queries.
@@ -230,6 +240,7 @@ public class PodDBAdapter {
public static final int IDX_FI_SMALL_FEED = 7;
public static final int IDX_FI_SMALL_HAS_CHAPTERS = 8;
public static final int IDX_FI_SMALL_ITEM_IDENTIFIER = 9;
+ public static final int IDX_FI_SMALL_FLATTR_STATUS = 10;
/**
* Select id, description and content-encoded column from feeditems.
@@ -311,6 +322,7 @@ public class PodDBAdapter {
values.put(KEY_LASTUPDATE, feed.getLastUpdate().getTime());
values.put(KEY_TYPE, feed.getType());
values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());
+ values.put(KEY_FLATTR_STATUS, feed.getFlattrStatus().toLong());
if (feed.getId() == 0) {
// Create new entry
if (AppConfig.DEBUG)
@@ -391,6 +403,7 @@ public class PodDBAdapter {
ContentValues values = new ContentValues();
values.put(KEY_POSITION, media.getPosition());
values.put(KEY_DURATION, media.getDuration());
+ values.put(KEY_PLAYED_DURATION, media.getPlayedDuration());
db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
new String[]{String.valueOf(media.getId())});
} else {
@@ -477,6 +490,7 @@ public class PodDBAdapter {
values.put(KEY_READ, item.isRead());
values.put(KEY_HAS_CHAPTERS, item.getChapters() != null);
values.put(KEY_ITEM_IDENTIFIER, item.getItemIdentifier());
+ values.put(KEY_FLATTR_STATUS, item.getFlattrStatus().toLong());
if (item.getId() == 0) {
item.setId(db.insert(TABLE_NAME_FEED_ITEMS, null, values));
} else {
@@ -1118,6 +1132,19 @@ public class PodDBAdapter {
}
feeditemCursor.close();
}
+ if (oldVersion <= 9) {
+ db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
+ + " ADD COLUMN " + KEY_FLATTR_STATUS
+ + " LONG");
+ db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_ITEMS
+ + " ADD COLUMN " + KEY_FLATTR_STATUS
+ + " LONG");
+ }
+ if (oldVersion <= 10) {
+ db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_MEDIA
+ + " ADD COLUMN " + KEY_PLAYED_DURATION
+ + " INTEGER");
+ }
}
}
}
diff --git a/src/de/danoeh/antennapod/util/flattr/FlattrStatus.java b/src/de/danoeh/antennapod/util/flattr/FlattrStatus.java
new file mode 100644
index 000000000..b7302d937
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/flattr/FlattrStatus.java
@@ -0,0 +1,67 @@
+package de.danoeh.antennapod.util.flattr;
+
+import java.util.Calendar;
+
+public class FlattrStatus {
+ private static final int STATUS_UNFLATTERED = 0;
+ private static final int STATUS_QUEUE = 1;
+ private static final int STATUS_FLATTRED = 2;
+
+ private int status = STATUS_UNFLATTERED;
+ private Calendar lastFlattred;
+
+ public FlattrStatus() {
+ lastFlattred = Calendar.getInstance();
+ }
+
+ public FlattrStatus(long status) {
+ lastFlattred = Calendar.getInstance();
+ fromLong(status);
+ }
+
+ public void setFlattred() {
+ status = STATUS_FLATTRED;
+ lastFlattred = Calendar.getInstance();
+ }
+
+ public void setUnflattred() {
+ status = STATUS_UNFLATTERED;
+ }
+
+ public boolean getUnflattred() {
+ return status == STATUS_UNFLATTERED;
+ }
+
+ public void setFlattrQueue() {
+ if (flattrable())
+ status = STATUS_QUEUE;
+ }
+
+ public void fromLong(long status) {
+ if (status == STATUS_UNFLATTERED || status == STATUS_QUEUE)
+ this.status = (int) status;
+ else {
+ this.status = STATUS_FLATTRED;
+ lastFlattred.setTimeInMillis(status);
+ }
+ }
+
+ public long toLong() {
+ if (status == STATUS_UNFLATTERED || status == STATUS_QUEUE)
+ return status;
+ else {
+ return lastFlattred.getTimeInMillis();
+ }
+ }
+
+ public boolean flattrable() {
+ Calendar firstOfMonth = Calendar.getInstance();
+ firstOfMonth.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMinimum(Calendar.DAY_OF_MONTH));
+
+ return (status == STATUS_UNFLATTERED) || (status == STATUS_FLATTRED && firstOfMonth.after(lastFlattred) );
+ }
+
+ public boolean getFlattrQueue() {
+ return status == STATUS_QUEUE;
+ }
+}
diff --git a/src/de/danoeh/antennapod/util/flattr/FlattrThing.java b/src/de/danoeh/antennapod/util/flattr/FlattrThing.java
new file mode 100644
index 000000000..f17ef1d83
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/flattr/FlattrThing.java
@@ -0,0 +1,7 @@
+package de.danoeh.antennapod.util.flattr;
+
+public interface FlattrThing {
+ public String getTitle();
+ public String getPaymentLink();
+ public FlattrStatus getFlattrStatus();
+}
diff --git a/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java b/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java
index ca2c9eb0f..869435f73 100644
--- a/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java
+++ b/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java
@@ -1,9 +1,16 @@
package de.danoeh.antennapod.util.flattr;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
import java.util.EnumSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.TimeZone;
import org.shredzone.flattr4j.FlattrService;
import org.shredzone.flattr4j.exception.FlattrException;
+import org.shredzone.flattr4j.model.Flattr;
import org.shredzone.flattr4j.model.Thing;
import org.shredzone.flattr4j.oauth.AccessToken;
import org.shredzone.flattr4j.oauth.AndroidAuthenticator;
@@ -119,6 +126,58 @@ public class FlattrUtils {
Log.e(TAG, "clickUrl was called with null access token");
}
}
+
+ public static List<Flattr> retrieveFlattredThings()
+ throws FlattrException {
+ ArrayList<Flattr> myFlattrs = new ArrayList<Flattr>();
+
+ if (hasToken()) {
+ FlattrService fs = FlattrServiceCreator.getService(retrieveToken());
+
+ Calendar firstOfMonth = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ firstOfMonth.set(Calendar.MILLISECOND, 0);
+ firstOfMonth.set(Calendar.SECOND, 0);
+ firstOfMonth.set(Calendar.MINUTE, 0);
+ firstOfMonth.set(Calendar.HOUR_OF_DAY, 0);
+ firstOfMonth.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMinimum(Calendar.DAY_OF_MONTH));
+
+ Date firstOfMonthDate = firstOfMonth.getTime();
+
+ // subscriptions some times get flattrd slightly before midnight - give it an hour leeway
+ firstOfMonthDate = new Date(firstOfMonthDate.getTime() - 60*60*1000);
+
+ final int FLATTR_COUNT = 30;
+ final int FLATTR_MAXPAGE = 5;
+
+ int page = 0;
+ do {
+ myFlattrs.ensureCapacity(FLATTR_COUNT*(page+1));
+
+ for (Flattr fl: fs.getMyFlattrs(FLATTR_COUNT, page)) {
+ if (fl.getCreated().after(firstOfMonthDate))
+ myFlattrs.add(fl);
+ else
+ break;
+ }
+ page++;
+ }
+ while (myFlattrs.get(myFlattrs.size()-1).getCreated().after( firstOfMonthDate ) && page < FLATTR_MAXPAGE);
+
+ if (AppConfig.DEBUG) {
+ Log.d(TAG, "Got my flattrs list of length " + Integer.toString(myFlattrs.size()) + " comparison date" + firstOfMonthDate);
+
+ for (Flattr fl: myFlattrs) {
+ Thing thing = fl.getThing();
+ Log.d(TAG, "Flattr thing: " + fl.getThingId() + " name: " + thing.getTitle() + " url: " + thing.getUrl() + " on: " + fl.getCreated());
+ }
+ }
+
+ } else {
+ Log.e(TAG, "retrieveFlattrdThings was called with null access token");
+ }
+
+ return myFlattrs;
+ }
public static void handleCallback(Context context, Uri uri) {
AndroidAuthenticator auth = createAuthenticator();
diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java
index e99a733dc..53316f9a4 100644
--- a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java
+++ b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java
@@ -14,6 +14,7 @@ import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.QueueAccess;
import de.danoeh.antennapod.util.ShareUtils;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
import java.util.List;
@@ -110,7 +111,7 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.visit_website_item, false);
}
- if (selectedItem.getPaymentLink() == null) {
+ if (selectedItem.getPaymentLink() == null || !selectedItem.getFlattrStatus().flattrable()) {
mi.setItemVisibility(R.id.support_item, false);
}
return true;
@@ -158,8 +159,9 @@ public class FeedItemMenuHandler {
context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
case R.id.support_item:
- new FlattrClickWorker(context, selectedItem.getPaymentLink())
- .executeAsync();
+ selectedItem.getFlattrStatus().setFlattrQueue();
+ DBWriter.setFlattredStatus(context, selectedItem);
+ new FlattrClickWorker(context).executeAsync();
break;
case R.id.share_link_item:
ShareUtils.shareFeedItemLink(context, selectedItem);
diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
index 446e024d9..ad3ded88b 100644
--- a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
+++ b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
@@ -19,6 +19,7 @@ import de.danoeh.antennapod.storage.DBWriter;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.ShareUtils;
+import de.danoeh.antennapod.util.flattr.FlattrStatus;
/** Handles interactions with the FeedItemMenu. */
public class FeedMenuHandler {
@@ -38,9 +39,10 @@ public class FeedMenuHandler {
Log.d(TAG, "Preparing options menu");
menu.findItem(R.id.mark_all_read_item).setVisible(
selectedFeed.hasNewItems(true));
- if (selectedFeed.getPaymentLink() != null) {
+ if (selectedFeed.getPaymentLink() != null && selectedFeed.getFlattrStatus().flattrable())
menu.findItem(R.id.support_item).setVisible(true);
- }
+ else
+ menu.findItem(R.id.support_item).setVisible(false);
MenuItem refresh = menu.findItem(R.id.refresh_item);
if (DownloadService.isRunning
&& DownloadRequester.getInstance().isDownloadingFile(
@@ -78,8 +80,9 @@ public class FeedMenuHandler {
context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
case R.id.support_item:
- new FlattrClickWorker(context, selectedFeed.getPaymentLink())
- .executeAsync();
+ selectedFeed.getFlattrStatus().setFlattrQueue();
+ DBWriter.setFlattredStatus(context, selectedFeed);
+ new FlattrClickWorker(context).executeAsync();
break;
case R.id.share_link_item:
ShareUtils.shareFeedlink(context, selectedFeed);