this consolidates the code from pull request #253 (flattr queue and auto flattr) into a single commit, rebased onto the current development branch

This commit is contained in:
Simon Rutishauser 2013-09-29 17:08:26 +02:00
parent 83bb0a6084
commit 8fbd1ecf9c
22 changed files with 693 additions and 84 deletions

View File

@ -10,6 +10,4 @@
# Project target.
proguard.config=proguard.cfg
target=android-18
android.library.reference.1=submodules/ActionBarSherlock/library
android.library.reference.2=submodules/ViewPagerIndicator/library
android.library.reference.3=submodules/dslv/library

View File

@ -151,9 +151,20 @@
<string name="action_forbidden_msg">AntennaPod has no permission for this action. The reason for this could be that the access token of AntennaPod to your account has been revoked. You can either re-reauthenticate or visit the website of the thing instead.</string>
<string name="access_revoked_title">Access revoked</string>
<string name="access_revoked_info">You have successfully revoked AntennaPod\'s access token to your account. In order to complete the process, you have to remove this app from the list of approved applications in your account settings on the flattr website.</string>
<string name="flattr_click_success">Successfully flattred this thing!</string>
<string name="flattring_label">Flattring</string>
<!-- Flattr -->
<string name="flattr_click_success">Flattred one thing!</string>
<string name="flattr_click_success_count">Flattred %d things!</string>
<string name="flattr_click_success_queue">Flattred: %s.</string>
<string name="flattr_click_failure_count">Failed to flattr %d things!</string>
<string name="flattr_click_failure">Not flattred: %s.</string>
<string name="flattr_click_enqueued">Added thing to flattr queue!</string>
<string name="flattring_thing">Flattring %s</string>
<string name="flattring_label">AntennaPod is flattring</string>
<string name="flattrd_label">AntennaPod has flattrd</string>
<string name="flattrd_failed_label">AntennaPod flattr failed</string>
<string name="flattr_retrieving_status">Retrieving flattred things</string>
<!-- Variable Speed -->
<string name="download_plugin_label">Download Plugin</string>
<string name="no_playback_plugin_title">Plugin Not Installed</string>
@ -190,6 +201,8 @@
<string name="pref_flattr_this_app_sum">Support the development of AntennaPod by flattring it. Thanks!</string>
<string name="pref_revokeAccess_title">Revoke access</string>
<string name="pref_revokeAccess_sum">Revoke the access permission to your flattr account for this app.</string>
<string name="pref_auto_flattr_title">Automatic Flattr</string>
<string name="pref_auto_flattr_sum">Flattr episodes of which 80% have been played.</string>
<string name="pref_display_only_episodes_title">Display only episodes</string>
<string name="pref_display_only_episodes_sum">Display only items which also have an episode.</string>
<string name="user_interface_label">User Interface</string>

View File

@ -80,6 +80,12 @@
<intent android:action=".activities.FlattrAuthActivity"/>
</PreferenceScreen>
<CheckBoxPreference
android:defaultValue="false"
android:enabled="false"
android:key="pref_auto_flattr"
android:summary="@string/pref_auto_flattr_sum"
android:title="@string/pref_auto_flattr_title" />
<Preference
android:key="prefRevokeAccess"
android:summary="@string/pref_revokeAccess_sum"
@ -106,7 +112,6 @@
android:key="pref_gpodnet_hostname"
android:title="@string/pref_gpodnet_sethostname_title"/>
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory android:title="@string/other_pref">
<Preference
@ -127,4 +132,4 @@
</PreferenceCategory>
</PreferenceScreen>
</PreferenceScreen>

View File

@ -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());

View File

@ -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());

View File

@ -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 SUCCESS:
onSuccess();
case EXIT_DEFAULT:
onFlattred();
break;
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();

View File

@ -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();
}
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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,

View File

@ -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;
}
}
}
}
}
}
}

View File

@ -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");
}
}
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,7 @@
package de.danoeh.antennapod.util.flattr;
public interface FlattrThing {
public String getTitle();
public String getPaymentLink();
public FlattrStatus getFlattrStatus();
}

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -74,7 +74,7 @@ public class DBTasksTest extends InstrumentationTestCase {
File f = new File(destFolder, "file " + i);
assertTrue(f.createNewFile());
files.add(f);
item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i)));
item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i), 0));
items.add(item);
}
@ -112,7 +112,7 @@ public class DBTasksTest extends InstrumentationTestCase {
assertTrue(f.createNewFile());
assertTrue(f.exists());
files.add(f);
item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i)));
item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i), 0));
items.add(item);
}
@ -146,7 +146,7 @@ public class DBTasksTest extends InstrumentationTestCase {
assertTrue(f.createNewFile());
assertTrue(f.exists());
files.add(f);
item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i)));
item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, new Date(NUM_ITEMS - i), 0));
items.add(item);
}

View File

@ -64,7 +64,7 @@ public class DBWriterTest extends InstrumentationTestCase {
feed.setItems(items);
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), true, feed);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null, 0);
item.setMedia(media);
items.add(item);
@ -108,7 +108,7 @@ public class DBWriterTest extends InstrumentationTestCase {
assertTrue(enc.createNewFile());
itemFiles.add(enc);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0);
item.setMedia(media);
}
@ -169,7 +169,7 @@ public class DBWriterTest extends InstrumentationTestCase {
assertTrue(enc.createNewFile());
itemFiles.add(enc);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0);
item.setMedia(media);
}
@ -317,7 +317,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File enc = new File(destFolder, "file " + i);
itemFiles.add(enc);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0);
item.setMedia(media);
}
@ -389,7 +389,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File enc = new File(destFolder, "file " + i);
itemFiles.add(enc);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0);
item.setMedia(media);
}
@ -430,7 +430,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), true, feed);
FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null, "url", false, playbackCompletionDate);
FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null, "url", false, playbackCompletionDate, 0);
feed.getItems().add(item);
item.setMedia(media);
PodDBAdapter adapter = new PodDBAdapter(context);