diff options
33 files changed, 519 insertions, 282 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java index bc1a40b11..355e0f372 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java @@ -15,7 +15,7 @@ import java.util.ArrayList; import java.util.List; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.opml.OpmlElement; +import de.danoeh.antennapod.core.export.opml.OpmlElement; import de.danoeh.antennapod.core.preferences.UserPreferences; /** @@ -23,10 +23,8 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; * which feeds he wants to import. */ public class OpmlFeedChooserActivity extends AppCompatActivity { - private static final String TAG = "OpmlFeedChooserActivity"; - public static final String EXTRA_SELECTED_ITEMS = "de.danoeh.antennapod.selectedItems"; - + private static final String TAG = "OpmlFeedChooserActivity"; private Button butConfirm; private Button butCancel; private ListView feedlist; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java index 8726af281..8b87aaaaf 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java @@ -20,7 +20,7 @@ import java.util.ArrayList; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.OpmlFeedQueuer; import de.danoeh.antennapod.asynctask.OpmlImportWorker; -import de.danoeh.antennapod.core.opml.OpmlElement; +import de.danoeh.antennapod.core.export.opml.OpmlElement; import de.danoeh.antennapod.core.util.LangUtils; /** @@ -29,9 +29,8 @@ import de.danoeh.antennapod.core.util.LangUtils; public class OpmlImportBaseActivity extends AppCompatActivity { private static final String TAG = "OpmlImportBaseActivity"; - private OpmlImportWorker importWorker; - private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5; + private OpmlImportWorker importWorker; @Nullable private Uri uri; /** diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java index 7afa270cc..b01cf43e4 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.activity; -import de.danoeh.antennapod.core.opml.OpmlElement; - import java.util.ArrayList; +import de.danoeh.antennapod.core.export.opml.OpmlElement; + /** * Hold infos gathered by Ompl-Import * <p/> diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java index 61765d6b7..dd932814f 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java @@ -26,11 +26,9 @@ import de.danoeh.antennapod.preferences.PreferenceController; */ public class PreferenceActivity extends AppCompatActivity { + private static WeakReference<PreferenceActivity> instance; private PreferenceController preferenceController; private MainFragment prefFragment; - private static WeakReference<PreferenceActivity> instance; - - private final PreferenceController.PreferenceUI preferenceUI = new PreferenceController.PreferenceUI() { @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override @@ -128,5 +126,14 @@ public class PreferenceActivity extends AppCompatActivity { } super.onPause(); } + + @Override + public void onStop() { + PreferenceActivity activity = instance.get(); + if(activity != null && activity.preferenceController != null) { + activity.preferenceController.onStop(); + } + super.onStop(); + } } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java index 4af988ea0..390bec15c 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java @@ -18,9 +18,6 @@ import de.danoeh.antennapod.preferences.PreferenceController; */ public class PreferenceActivityGingerbread extends android.preference.PreferenceActivity { private static final String TAG = "PreferenceActivity"; - - private PreferenceController preferenceController; - private final PreferenceController.PreferenceUI preferenceUI = new PreferenceController.PreferenceUI() { @SuppressWarnings("deprecation") @@ -34,6 +31,7 @@ public class PreferenceActivityGingerbread extends android.preference.Preference return PreferenceActivityGingerbread.this; } }; + private PreferenceController preferenceController; @SuppressLint("NewApi") @SuppressWarnings("deprecation") @@ -61,6 +59,12 @@ public class PreferenceActivityGingerbread extends android.preference.Preference } @Override + protected void onStop() { + preferenceController.onStop(); + super.onStop(); + } + + @Override protected void onApplyThemeResource(Theme theme, int resid, boolean first) { theme.applyStyle(UserPreferences.getTheme(), true); } diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java new file mode 100644 index 000000000..192df8ca5 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java @@ -0,0 +1,65 @@ +package de.danoeh.antennapod.asynctask; + +import android.support.annotation.NonNull; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; + +import de.danoeh.antennapod.core.export.ExportWriter; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.util.LangUtils; +import rx.Observable; + +/** + * Writes an OPML file into the export directory in the background. + */ +public class ExportWorker { + + private static final String EXPORT_DIR = "export/"; + private static final String TAG = "ExportWorker"; + private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds"; + + private ExportWriter exportWriter; + private File output; + + public ExportWorker(ExportWriter exportWriter) { + this(exportWriter, new File(UserPreferences.getDataFolder(EXPORT_DIR), + DEFAULT_OUTPUT_NAME + "." + exportWriter.fileExtension())); + } + + public ExportWorker(ExportWriter exportWriter, @NonNull File output) { + this.exportWriter = exportWriter; + this.output = output; + } + + public Observable<File> exportObservable() { + if (output.exists()) { + Log.w(TAG, "Overwriting previously exported file."); + output.delete(); + } + return Observable.create(subscriber -> { + OutputStreamWriter writer = null; + try { + writer = new OutputStreamWriter(new FileOutputStream(output), LangUtils.UTF_8); + exportWriter.writeDocument(DBReader.getFeedList(), writer); + subscriber.onNext(output); + } catch (IOException e) { + subscriber.onError(e); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + subscriber.onError(e); + } + } + subscriber.onCompleted(); + } + }); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java deleted file mode 100644 index 13abb26ea..000000000 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java +++ /dev/null @@ -1,122 +0,0 @@ -package de.danoeh.antennapod.asynctask; - -import android.annotation.SuppressLint; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.AsyncTask; -import android.support.v7.app.AlertDialog; -import android.util.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; - -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.core.opml.OpmlWriter; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.storage.DBReader; -import de.danoeh.antennapod.core.util.LangUtils; - -/** - * Writes an OPML file into the export directory in the background. - */ -public class OpmlExportWorker extends AsyncTask<Void, Void, Void> { - private static final String TAG = "OpmlExportWorker"; - private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds.opml"; - public static final String EXPORT_DIR = "export/"; - - private Context context; - private File output; - - private ProgressDialog progDialog; - private Exception exception; - - public OpmlExportWorker(Context context, File output) { - this.context = context; - this.output = output; - } - - public OpmlExportWorker(Context context) { - this.context = context; - } - - @Override - protected Void doInBackground(Void... params) { - OpmlWriter opmlWriter = new OpmlWriter(); - if (output == null) { - output = new File( - UserPreferences.getDataFolder(EXPORT_DIR), - DEFAULT_OUTPUT_NAME); - if (output.exists()) { - Log.w(TAG, "Overwriting previously exported file."); - output.delete(); - } - } - OutputStreamWriter writer = null; - try { - writer = new OutputStreamWriter(new FileOutputStream(output), LangUtils.UTF_8); - opmlWriter.writeDocument(DBReader.getFeedList(), writer); - } catch (IOException e) { - e.printStackTrace(); - exception = e; - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException ioe) { - exception = ioe; - } - } - } - return null; - } - - @Override - protected void onPostExecute(Void result) { - progDialog.dismiss(); - AlertDialog.Builder alert = new AlertDialog.Builder(context) - .setNeutralButton(android.R.string.ok, - (dialog, which) -> dialog.dismiss()); - if (exception != null) { - alert.setTitle(R.string.export_error_label); - alert.setMessage(exception.getMessage()); - } else { - alert.setTitle(R.string.opml_export_success_title); - alert.setMessage(context - .getString(R.string.opml_export_success_sum) - + output.toString()) - .setPositiveButton(R.string.send_label, (dialog, which) -> { - Uri outputUri = Uri.fromFile(output); - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, - context.getResources().getText(R.string.opml_export_label)); - sendIntent.putExtra(Intent.EXTRA_STREAM, outputUri); - sendIntent.setType("text/plain"); - context.startActivity(Intent.createChooser(sendIntent, - context.getResources().getText(R.string.send_label))); - }); - } - alert.create().show(); - } - - @Override - protected void onPreExecute() { - progDialog = new ProgressDialog(context); - progDialog.setMessage(context.getString(R.string.exporting_label)); - progDialog.setIndeterminate(true); - progDialog.show(); - } - - @SuppressLint("NewApi") - public void executeAsync() { - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - executeOnExecutor(THREAD_POOL_EXECUTOR); - } else { - execute(); - } - } - -} diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java index 1cb653f01..4449d82c2 100644 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java @@ -9,8 +9,8 @@ import java.util.Arrays; import de.danoeh.antennapod.activity.OpmlImportHolder; import de.danoeh.antennapod.core.R; +import de.danoeh.antennapod.core.export.opml.OpmlElement; import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.opml.OpmlElement; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java index f3b3aeca9..62ea85811 100644 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java @@ -14,8 +14,8 @@ import java.io.Reader; import java.util.ArrayList; import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.core.opml.OpmlElement; -import de.danoeh.antennapod.core.opml.OpmlReader; +import de.danoeh.antennapod.core.export.opml.OpmlElement; +import de.danoeh.antennapod.core.export.opml.OpmlReader; public class OpmlImportWorker extends AsyncTask<Void, Void, ArrayList<OpmlElement>> { diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java index 577a3ecbe..202d33408 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -225,6 +225,9 @@ public class EpisodesApplyActionFragment extends Fragment { checkQueued(false); resId = R.string.selected_not_queued_label; break; + case R.id.check_has_media: + checkWithMedia(); + resId = R.string.selected_has_media_label; case R.id.sort_title_a_z: sortByTitle(false); return true; @@ -357,6 +360,17 @@ public class EpisodesApplyActionFragment extends Fragment { refreshCheckboxes(); } + private void checkWithMedia() { + for (FeedItem episode : episodes) { + if(episode.hasMedia()) { + checkedIds.add(episode.getId()); + } else { + checkedIds.remove(episode.getId()); + } + } + refreshCheckboxes(); + } + private void refreshTitles() { titles.clear(); for(FeedItem episode : episodes) { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java index 29df6617d..ab8808093 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -227,22 +227,32 @@ public class AllEpisodesFragment extends Fragment { } return true; case R.id.mark_all_read_item: - ConfirmationDialog conDialog = new ConfirmationDialog(getActivity(), + ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(), R.string.mark_all_read_label, R.string.mark_all_read_confirmation_msg) { @Override - public void onConfirmButtonPressed( - DialogInterface dialog) { + public void onConfirmButtonPressed(DialogInterface dialog) { dialog.dismiss(); DBWriter.markAllItemsRead(); Toast.makeText(getActivity(), R.string.mark_all_read_msg, Toast.LENGTH_SHORT).show(); } }; - conDialog.createNewDialog().show(); + markAllReadConfirmationDialog.createNewDialog().show(); return true; case R.id.mark_all_seen_item: - DBWriter.markNewItemsSeen(); + ConfirmationDialog markAllSeenConfirmationDialog = new ConfirmationDialog(getActivity(), + R.string.mark_all_seen_label, + R.string.mark_all_seen_confirmation_msg) { + + @Override + public void onConfirmButtonPressed(DialogInterface dialog) { + dialog.dismiss(); + DBWriter.markNewItemsSeen(); + Toast.makeText(getActivity(), R.string.mark_all_seen_msg, Toast.LENGTH_SHORT).show(); + } + }; + markAllSeenConfirmationDialog.createNewDialog().show(); return true; default: return false; diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java index 19b8361e6..818b3a625 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java @@ -3,6 +3,7 @@ package de.danoeh.antennapod.preferences; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.ProgressDialog; import android.app.TimePickerDialog; import android.content.ActivityNotFoundException; import android.content.Context; @@ -54,7 +55,10 @@ import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.activity.PreferenceActivityGingerbread; import de.danoeh.antennapod.activity.StatisticsActivity; -import de.danoeh.antennapod.asynctask.OpmlExportWorker; +import de.danoeh.antennapod.asynctask.ExportWorker; +import de.danoeh.antennapod.core.export.ExportWriter; +import de.danoeh.antennapod.core.export.html.HtmlWriter; +import de.danoeh.antennapod.core.export.opml.OpmlWriter; import de.danoeh.antennapod.core.preferences.GpodnetPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.GpodnetSyncService; @@ -66,6 +70,10 @@ import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog; import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog; import de.danoeh.antennapod.dialog.ProxyDialog; import de.danoeh.antennapod.dialog.VariableSpeedDialog; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Sets up a preference UI that lets the user change user preferences. @@ -75,53 +83,34 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc private static final String TAG = "PreferenceController"; - public static final String PREF_FLATTR_SETTINGS = "prefFlattrSettings"; - public static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate"; - public static final String PREF_FLATTR_REVOKE = "prefRevokeAccess"; - public static final String PREF_AUTO_FLATTR_PREFS = "prefAutoFlattrPrefs"; - public static final String PREF_OPML_EXPORT = "prefOpmlExport"; - public static final String STATISTICS = "statistics"; - public static final String PREF_ABOUT = "prefAbout"; - public static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir"; - public static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings"; - public static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher"; - public static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate"; - public static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information"; - public static final String PREF_GPODNET_SYNC = "pref_gpodnet_sync"; - public static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout"; - public static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname"; - public static final String PREF_GPODNET_NOTIFICATIONS = "pref_gpodnet_notifications"; - public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify"; - public static final String PREF_PROXY = "prefProxy"; - public static final String PREF_KNOWN_ISSUES = "prefKnownIssues"; - public static final String PREF_FAQ = "prefFaq"; - public static final String PREF_SEND_CRASH_REPORT = "prefSendCrashReport"; - - private final PreferenceUI ui; - - private CheckBoxPreference[] selectedNetworks; - + private static final String PREF_FLATTR_SETTINGS = "prefFlattrSettings"; + 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_PREFS = "prefAutoFlattrPrefs"; + private static final String PREF_OPML_EXPORT = "prefOpmlExport"; + private static final String PREF_HTML_EXPORT = "prefHtmlExport"; + private static final String STATISTICS = "statistics"; + private static final String PREF_ABOUT = "prefAbout"; + private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir"; + private static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings"; + private static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher"; + private static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate"; + private static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information"; + private static final String PREF_GPODNET_SYNC = "pref_gpodnet_sync"; + private static final String PREF_GPODNET_FORCE_FULL_SYNC = "pref_gpodnet_force_full_sync"; + private static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout"; + private static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname"; + private static final String PREF_GPODNET_NOTIFICATIONS = "pref_gpodnet_notifications"; + private static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify"; + private static final String PREF_PROXY = "prefProxy"; + private static final String PREF_KNOWN_ISSUES = "prefKnownIssues"; + private static final String PREF_FAQ = "prefFaq"; + private static final String PREF_SEND_CRASH_REPORT = "prefSendCrashReport"; private static final String[] EXTERNAL_STORAGE_PERMISSIONS = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41; - - public PreferenceController(PreferenceUI ui) { - this.ui = ui; - PreferenceManager.getDefaultSharedPreferences(ui.getActivity().getApplicationContext()) - .registerOnSharedPreferenceChangeListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if(key.equals(UserPreferences.PREF_SONIC)) { - CheckBoxPreference prefSonic = (CheckBoxPreference) ui.findPreference(UserPreferences.PREF_SONIC); - if(prefSonic != null) { - prefSonic.setChecked(sharedPreferences.getBoolean(UserPreferences.PREF_SONIC, false)); - } - } - } - + private final PreferenceUI ui; private final SharedPreferences.OnSharedPreferenceChangeListener gpoddernetListener = (sharedPreferences, key) -> { if (GpodnetPreferences.PREF_LAST_SYNC_ATTEMPT_TIMESTAMP.equals(key)) { @@ -129,6 +118,14 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc GpodnetPreferences.getLastSyncAttemptTimestamp()); } }; + private CheckBoxPreference[] selectedNetworks; + private Subscription subscription; + + public PreferenceController(PreferenceUI ui) { + this.ui = ui; + PreferenceManager.getDefaultSharedPreferences(ui.getActivity().getApplicationContext()) + .registerOnSharedPreferenceChangeListener(this); + } /** * Returns the preference activity that should be used on this device. @@ -143,6 +140,16 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc } } + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if(key.equals(UserPreferences.PREF_SONIC)) { + CheckBoxPreference prefSonic = (CheckBoxPreference) ui.findPreference(UserPreferences.PREF_SONIC); + if(prefSonic != null) { + prefSonic.setChecked(sharedPreferences.getBoolean(UserPreferences.PREF_SONIC, false)); + } + } + } + public void onCreate() { final Activity activity = ui.getActivity(); @@ -178,11 +185,9 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc } ); ui.findPreference(PreferenceController.PREF_OPML_EXPORT).setOnPreferenceClickListener( - preference -> { - new OpmlExportWorker(activity).executeAsync(); - return true; - } - ); + preference -> export(new OpmlWriter())); + ui.findPreference(PreferenceController.PREF_HTML_EXPORT).setOnPreferenceClickListener( + preference -> export(new HtmlWriter())); ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener( preference -> { if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT && @@ -348,6 +353,18 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc toast.show(); return true; }); + ui.findPreference(PreferenceController.PREF_GPODNET_FORCE_FULL_SYNC). + setOnPreferenceClickListener(preference -> { + GpodnetPreferences.setLastSubscriptionSyncTimestamp(0L); + GpodnetPreferences.setLastEpisodeActionsSyncTimestamp(0L); + GpodnetPreferences.setLastSyncAttempt(false, 0); + updateLastGpodnetSyncReport(false, 0); + GpodnetSyncService.sendSyncIntent(ui.getActivity().getApplicationContext()); + Toast toast = Toast.makeText(ui.getActivity(), R.string.pref_gpodnet_sync_started, + Toast.LENGTH_SHORT); + toast.show(); + return true; + }); ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener( preference -> { GpodnetPreferences.logout(); @@ -427,6 +444,40 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc setSelectedNetworksEnabled(UserPreferences.isEnableAutodownloadWifiFilter()); } + private boolean export(ExportWriter exportWriter) { + Context context = ui.getActivity(); + final ProgressDialog progressDialog = new ProgressDialog(context); + progressDialog.setMessage(context.getString(R.string.exporting_label)); + progressDialog.setIndeterminate(true); + progressDialog.show(); + final AlertDialog.Builder alert = new AlertDialog.Builder(context) + .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss()); + Observable<File> observable = new ExportWorker(exportWriter).exportObservable(); + subscription = observable.subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(output -> { + alert.setTitle(R.string.opml_export_success_title); + String message = context.getString(R.string.opml_export_success_sum) + output.toString(); + alert.setMessage(message); + alert.setPositiveButton(R.string.send_label, (dialog, which) -> { + Uri outputUri = Uri.fromFile(output); + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_SUBJECT, + context.getResources().getText(R.string.opml_export_label)); + sendIntent.putExtra(Intent.EXTRA_STREAM, outputUri); + sendIntent.setType("text/plain"); + context.startActivity(Intent.createChooser(sendIntent, + context.getResources().getText(R.string.send_label))); + }); + alert.create().show(); + }, error -> { + alert.setTitle(R.string.export_error_label); + alert.setMessage(error.getMessage()); + alert.show(); + }, () -> progressDialog.dismiss()); + return true; + } + private void openInBrowser(String url) { try { Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); @@ -451,6 +502,12 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc GpodnetPreferences.unregisterOnSharedPreferenceChangeListener(gpoddernetListener); } + public void onStop() { + if(subscription != null) { + subscription.unsubscribe(); + } + } + @SuppressLint("NewApi") public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK && @@ -492,6 +549,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc ui.findPreference(PreferenceController.PREF_GPODNET_LOGIN).setEnabled(!loggedIn); ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION).setEnabled(loggedIn); ui.findPreference(PreferenceController.PREF_GPODNET_SYNC).setEnabled(loggedIn); + ui.findPreference(PreferenceController.PREF_GPODNET_FORCE_FULL_SYNC).setEnabled(loggedIn); ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setEnabled(loggedIn); ui.findPreference(PREF_GPODNET_NOTIFICATIONS).setEnabled(loggedIn); if(loggedIn) { @@ -511,7 +569,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc private void updateLastGpodnetSyncReport(boolean successful, long lastTime) { Preference sync = ui.findPreference(PREF_GPODNET_SYNC); if (lastTime != 0) { - sync.setSummary(ui.getActivity().getString(R.string.pref_gpodnet_sync_sum) + "\n" + + sync.setSummary(ui.getActivity().getString(R.string.pref_gpodnet_sync_changes_sum) + "\n" + ui.getActivity().getString(R.string.pref_gpodnet_sync_sum_last_sync_line, ui.getActivity().getString(successful ? R.string.gpodnetsync_pref_report_successful : @@ -522,7 +580,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME))); } else { - sync.setSummary(ui.getActivity().getString(R.string.pref_gpodnet_sync_sum)); + sync.setSummary(ui.getActivity().getString(R.string.pref_gpodnet_sync_changes_sum)); } } @@ -774,9 +832,8 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]); } }); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { - UserPreferences.setHiddenDrawerItems(hiddenDrawerItems); - }); + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> + UserPreferences.setHiddenDrawerItems(hiddenDrawerItems)); builder.setNegativeButton(R.string.cancel_label, null); builder.create().show(); } @@ -820,9 +877,8 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc preferredButtons.remove((Integer) which); } }); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { - UserPreferences.setCompactNotificationButtons(preferredButtons); - }); + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> + UserPreferences.setCompactNotificationButtons(preferredButtons)); builder.setNegativeButton(R.string.cancel_label, null); builder.create().show(); } diff --git a/app/src/main/res/menu/episodes_apply_action_options.xml b/app/src/main/res/menu/episodes_apply_action_options.xml index 3df88046d..c3f117386 100644 --- a/app/src/main/res/menu/episodes_apply_action_options.xml +++ b/app/src/main/res/menu/episodes_apply_action_options.xml @@ -46,6 +46,8 @@ android:title="@string/queued_label"/> <item android:id="@+id/check_not_queued" android:title="@string/not_queued_label"/> + <item android:id="@+id/check_has_media" + android:title="@string/has_media"/> </menu> </item> diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 350e2e2ee..fab96338e 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -253,8 +253,12 @@ android:summary="@string/pref_gpodnet_setlogin_information_sum"/> <Preference android:key="pref_gpodnet_sync" - android:title="@string/pref_gpodnet_sync_title" - android:summary="@string/pref_gpodnet_sync_sum"/> + android:title="@string/pref_gpodnet_sync_changes_title" + android:summary="@string/pref_gpodnet_sync_changes_sum"/> + <Preference + android:key="pref_gpodnet_force_full_sync" + android:title="@string/pref_gpodnet_full_sync_title" + android:summary="@string/pref_gpodnet_full_sync_sum"/> <Preference android:key="pref_gpodnet_logout" android:title="@string/pref_gpodnet_logout_title"/> @@ -285,6 +289,9 @@ android:key="prefOpmlExport" android:title="@string/opml_export_label"/> <Preference + android:key="prefHtmlExport" + android:title="@string/html_export_label"/> + <Preference android:key="statistics" android:title="@string/statistics_label"/> </PreferenceCategory> diff --git a/build.gradle b/build.gradle index 221f5a68c..eddcd91d5 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,8 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.0' - classpath "me.tatarka:gradle-retrolambda:3.3.0" + classpath 'com.android.tools.build:gradle:2.2.2' + classpath "me.tatarka:gradle-retrolambda:3.3.1" classpath "me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2" classpath 'com.github.triplet.gradle:play-publisher:1.1.4' // Exclude the version that the android plugin depends on. diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java index e475e696c..67c460e78 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FeedRemover.java @@ -38,10 +38,11 @@ public class FeedRemover extends AsyncTask<Void, Void, Void> { @Override protected void onPostExecute(Void result) { - dialog.dismiss(); + if(dialog != null && dialog.isShowing()) { + dialog.dismiss(); + } if(skipOnCompletion) { - context.sendBroadcast(new Intent( - PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); + context.sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java index 982015314..80ce6cf56 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java @@ -8,6 +8,7 @@ import android.content.Context; import android.os.ParcelFileDescriptor; import android.util.Log; +import org.apache.commons.io.IOUtils; import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayOutputStream; @@ -27,10 +28,10 @@ import java.util.ArrayList; import java.util.Arrays; import de.danoeh.antennapod.core.BuildConfig; +import de.danoeh.antennapod.core.export.opml.OpmlElement; +import de.danoeh.antennapod.core.export.opml.OpmlReader; +import de.danoeh.antennapod.core.export.opml.OpmlWriter; import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.opml.OpmlElement; -import de.danoeh.antennapod.core.opml.OpmlReader; -import de.danoeh.antennapod.core.opml.OpmlWriter; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; @@ -56,7 +57,9 @@ public class OpmlBackupAgent extends BackupAgentHelper { } } - /** Class for backing up and restoring the OPML file. */ + /** + * Class for backing up and restoring the OPML file. + */ private static class OpmlBackupHelper implements BackupHelper { private static final String TAG = "OpmlBackupHelper"; @@ -64,7 +67,9 @@ public class OpmlBackupAgent extends BackupAgentHelper { private final Context mContext; - /** Checksum of restored OPML file */ + /** + * Checksum of restored OPML file + */ private byte[] mChecksum; public OpmlBackupHelper(Context context) { @@ -170,12 +175,7 @@ public class OpmlBackupAgent extends BackupAgentHelper { } catch (IOException e) { Log.e(TAG, "Failed to restore OPML backup", e); } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - } - } + IOUtils.closeQuietly(reader); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/CommonSymbols.java b/core/src/main/java/de/danoeh/antennapod/core/export/CommonSymbols.java new file mode 100644 index 000000000..020a0671f --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/export/CommonSymbols.java @@ -0,0 +1,22 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.danoeh.antennapod.core.export; + +public class CommonSymbols { + + public static final String HEAD = "head"; + public static final String BODY = "body"; + public static final String TITLE = "title"; + +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/ExportWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/ExportWriter.java new file mode 100644 index 000000000..d6a187b21 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/export/ExportWriter.java @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.danoeh.antennapod.core.export; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; + +import de.danoeh.antennapod.core.feed.Feed; + +public interface ExportWriter { + + void writeDocument(List<Feed> feeds, Writer writer) + throws IllegalArgumentException, IllegalStateException, IOException; + + String fileExtension(); + +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlSymbols.java b/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlSymbols.java new file mode 100644 index 000000000..b8807a686 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlSymbols.java @@ -0,0 +1,30 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.danoeh.antennapod.core.export.html; + +import de.danoeh.antennapod.core.export.CommonSymbols; + +class HtmlSymbols extends CommonSymbols { + + static final String HTML = "html"; + + static final String ORDERED_LIST = "ol"; + static final String LIST_ITEM = "li"; + + static String HEADING = "h1"; + + static final String LINK = "a"; + static final String LINK_DESTINATION = "href"; + +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java new file mode 100644 index 000000000..2fdd8ffa6 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java @@ -0,0 +1,92 @@ +package de.danoeh.antennapod.core.export.html; + +import android.text.TextUtils; +import android.util.Log; +import android.util.Xml; + +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; + +import de.danoeh.antennapod.core.export.ExportWriter; +import de.danoeh.antennapod.core.feed.Feed; + +/** Writes HTML documents. */ +public class HtmlWriter implements ExportWriter { + + private static final String TAG = "HtmlWriter"; + private static final String ENCODING = "UTF-8"; + private static final String HTML_TITLE = "AntennaPod Subscriptions"; + + /** + * Takes a list of feeds and a writer and writes those into an HTML + * document. + * + * @throws IOException + * @throws IllegalStateException + * @throws IllegalArgumentException + */ + @Override + public void writeDocument(List<Feed> feeds, Writer writer) + throws IllegalArgumentException, IllegalStateException, IOException { + Log.d(TAG, "Starting to write document"); + XmlSerializer xs = Xml.newSerializer(); + xs.setOutput(writer); + + xs.startDocument(ENCODING, false); + xs.text("\n"); + xs.startTag(null, HtmlSymbols.HTML); + xs.text("\n"); + xs.startTag(null, HtmlSymbols.HEAD); + xs.text("\n"); + xs.startTag(null, HtmlSymbols.TITLE); + xs.text(HTML_TITLE); + xs.endTag(null, HtmlSymbols.TITLE); + xs.text("\n"); + xs.endTag(null, HtmlSymbols.HEAD); + xs.text("\n"); + + xs.startTag(null, HtmlSymbols.BODY); + xs.text("\n"); + xs.startTag(null, HtmlSymbols.HEADING); + xs.text(HTML_TITLE); + xs.endTag(null, HtmlSymbols.HEADING); + xs.text("\n"); + xs.startTag(null, HtmlSymbols.ORDERED_LIST); + xs.text("\n"); + for (Feed feed : feeds) { + xs.startTag(null, HtmlSymbols.LIST_ITEM); + xs.text(feed.getTitle()); + if (!TextUtils.isEmpty(feed.getLink())) { + xs.text(" ["); + xs.startTag(null, HtmlSymbols.LINK); + xs.attribute(null, HtmlSymbols.LINK_DESTINATION, feed.getLink()); + xs.text("Website"); + xs.endTag(null, HtmlSymbols.LINK); + xs.text("]"); + } + xs.text(" ["); + xs.startTag(null, HtmlSymbols.LINK); + xs.attribute(null, HtmlSymbols.LINK_DESTINATION, feed.getDownload_url()); + xs.text("Feed"); + xs.endTag(null, HtmlSymbols.LINK); + xs.text("]"); + xs.endTag(null, HtmlSymbols.LIST_ITEM); + xs.text("\n"); + } + xs.endTag(null, HtmlSymbols.ORDERED_LIST); + xs.endTag(null, HtmlSymbols.BODY); + xs.text("\n"); + xs.endTag(null, HtmlSymbols.HTML); + xs.text("\n"); + xs.endDocument(); + Log.d(TAG, "Finished writing document"); + } + + public String fileExtension() { + return "html"; + } + +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlElement.java b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlElement.java index 8d0a4a842..61eb4d0c9 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlElement.java +++ b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlElement.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.opml; +package de.danoeh.antennapod.core.export.opml; /** Represents a single feed in an OPML file. */ public class OpmlElement { diff --git a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlReader.java index 17afc7904..a17fedd7d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlReader.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.opml; +package de.danoeh.antennapod.core.export.opml; import android.util.Log; diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlSymbols.java b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlSymbols.java new file mode 100644 index 000000000..40b0e23b8 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlSymbols.java @@ -0,0 +1,21 @@ +package de.danoeh.antennapod.core.export.opml; + +import de.danoeh.antennapod.core.export.CommonSymbols; + +/** Contains symbols for reading and writing OPML documents. */ +public final class OpmlSymbols extends CommonSymbols { + + public static final String OPML = "opml"; + static final String OUTLINE = "outline"; + static final String TEXT = "text"; + static final String XMLURL = "xmlUrl"; + static final String HTMLURL = "htmlUrl"; + static final String TYPE = "type"; + static final String VERSION = "version"; + static final String DATE_CREATED = "dateCreated"; + + private OpmlSymbols() { + + } + +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java index 673c602df..afd652cff 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.opml; +package de.danoeh.antennapod.core.export.opml; import android.util.Log; import android.util.Xml; @@ -10,11 +10,13 @@ import java.io.Writer; import java.util.Date; import java.util.List; +import de.danoeh.antennapod.core.export.ExportWriter; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.util.DateUtils; /** Writes OPML documents. */ -public class OpmlWriter { +public class OpmlWriter implements ExportWriter { + private static final String TAG = "OpmlWriter"; private static final String ENCODING = "UTF-8"; private static final String OPML_VERSION = "2.0"; @@ -28,6 +30,7 @@ public class OpmlWriter { * @throws IllegalStateException * @throws IllegalArgumentException */ + @Override public void writeDocument(List<Feed> feeds, Writer writer) throws IllegalArgumentException, IllegalStateException, IOException { Log.d(TAG, "Starting to write document"); @@ -83,4 +86,9 @@ public class OpmlWriter { xs.endDocument(); Log.d(TAG, "Finished writing document"); } + + public String fileExtension() { + return "opml"; + } + } diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java index 9d8f4adf8..200153876 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java @@ -18,6 +18,7 @@ public class FeedItemFilter { private boolean showNotQueued = false; private boolean showDownloaded = false; private boolean showNotDownloaded = false; + private boolean showHasMedia = false; public FeedItemFilter(String properties) { this(TextUtils.split(properties, ",")); @@ -49,6 +50,9 @@ public class FeedItemFilter { case "not_downloaded": showNotDownloaded = true; break; + case "has_media": + showHasMedia = true; + break; } } } @@ -82,6 +86,8 @@ public class FeedItemFilter { if (showDownloaded && !downloaded) continue; if (showNotDownloaded && downloaded) continue; + if (showHasMedia && !item.hasMedia()) continue; + // If the item reaches here, it meets all criteria result.add(item); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlSymbols.java b/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlSymbols.java deleted file mode 100644 index c973713cb..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/opml/OpmlSymbols.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.danoeh.antennapod.core.opml; - -/** Contains symbols for reading and writing OPML documents. */ -public final class OpmlSymbols { - - public static final String OPML = "opml"; - public static final String BODY = "body"; - public static final String OUTLINE = "outline"; - public static final String TEXT = "text"; - public static final String XMLURL = "xmlUrl"; - public static final String HTMLURL = "htmlUrl"; - public static final String TYPE = "type"; - public static final String VERSION = "version"; - public static final String HEAD = "head"; - public static final String TITLE = "title"; - public static final String DATE_CREATED = "dateCreated"; - - private OpmlSymbols() { - - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java index 0871758d0..cad67539b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java @@ -383,6 +383,9 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { statusBeforeSeeking = playerStatus; setPlayerStatus(PlayerStatus.SEEKING, media, getPosition()); mediaPlayer.seekTo(t); + if (statusBeforeSeeking == PlayerStatus.PREPARED) { + media.setPosition(t); + } try { seekLatch.await(3, TimeUnit.SECONDS); } catch (InterruptedException e) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java index 47503dee4..ae91c0743 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java @@ -6,7 +6,6 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.syndication.namespace.NSContent; import de.danoeh.antennapod.core.syndication.namespace.NSDublinCore; @@ -86,34 +85,28 @@ public class SyndHandler extends DefaultHandler { state.defaultNamespaces.push(new NSAtom()); } else if (prefix.equals(NSAtom.NSTAG)) { state.namespaces.put(uri, new NSAtom()); - if (BuildConfig.DEBUG) - Log.d(TAG, "Recognized Atom namespace"); + Log.d(TAG, "Recognized Atom namespace"); } } else if (uri.equals(NSContent.NSURI) && prefix.equals(NSContent.NSTAG)) { state.namespaces.put(uri, new NSContent()); - if (BuildConfig.DEBUG) - Log.d(TAG, "Recognized Content namespace"); + Log.d(TAG, "Recognized Content namespace"); } else if (uri.equals(NSITunes.NSURI) && prefix.equals(NSITunes.NSTAG)) { state.namespaces.put(uri, new NSITunes()); - if (BuildConfig.DEBUG) - Log.d(TAG, "Recognized ITunes namespace"); + Log.d(TAG, "Recognized ITunes namespace"); } else if (uri.equals(NSSimpleChapters.NSURI) && prefix.matches(NSSimpleChapters.NSTAG)) { state.namespaces.put(uri, new NSSimpleChapters()); - if (BuildConfig.DEBUG) - Log.d(TAG, "Recognized SimpleChapters namespace"); + Log.d(TAG, "Recognized SimpleChapters namespace"); } else if (uri.equals(NSMedia.NSURI) && prefix.equals(NSMedia.NSTAG)) { state.namespaces.put(uri, new NSMedia()); - if (BuildConfig.DEBUG) - Log.d(TAG, "Recognized media namespace"); + Log.d(TAG, "Recognized media namespace"); } else if (uri.equals(NSDublinCore.NSURI) && prefix.equals(NSDublinCore.NSTAG)) { state.namespaces.put(uri, new NSDublinCore()); - if (BuildConfig.DEBUG) - Log.d(TAG, "Recognized DublinCore namespace"); + Log.d(TAG, "Recognized DublinCore namespace"); } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java index a5ca9d6f4..c91444552 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java @@ -20,25 +20,27 @@ import de.danoeh.antennapod.core.util.DateUtils; * */ public class NSRSS20 extends Namespace { - private static final String TAG = "NSRSS20"; - public static final String NSTAG = "rss"; - public static final String NSURI = ""; - public static final String CHANNEL = "channel"; + private static final String TAG = "NSRSS20"; + + private static final String NSTAG = "rss"; + private static final String NSURI = ""; + + public static final String CHANNEL = "channel"; public static final String ITEM = "item"; - public static final String GUID = "guid"; - public static final String TITLE = "title"; - public static final String LINK = "link"; - public static final String DESCR = "description"; - public static final String PUBDATE = "pubDate"; - public static final String ENCLOSURE = "enclosure"; - public static final String IMAGE = "image"; - public static final String URL = "url"; - public static final String LANGUAGE = "language"; + private static final String GUID = "guid"; + private static final String TITLE = "title"; + private static final String LINK = "link"; + private static final String DESCR = "description"; + private static final String PUBDATE = "pubDate"; + private static final String ENCLOSURE = "enclosure"; + private static final String IMAGE = "image"; + private static final String URL = "url"; + private static final String LANGUAGE = "language"; - public static final String ENC_URL = "url"; - public static final String ENC_LEN = "length"; - public static final String ENC_TYPE = "type"; + private static final String ENC_URL = "url"; + private static final String ENC_LEN = "length"; + private static final String ENC_TYPE = "type"; @Override public SyndElement handleElementStart(String localName, HandlerState state, @@ -55,11 +57,12 @@ public class NSRSS20 extends Namespace { if(SyndTypeUtils.enclosureTypeValid(type)) { validType = true; } else { - type = type = SyndTypeUtils.getValidMimeTypeFromUrl(url); + type = SyndTypeUtils.getValidMimeTypeFromUrl(url); validType = type != null; } + boolean validUrl = !TextUtils.isEmpty(url); if (state.getCurrentItem() != null && state.getCurrentItem().getMedia() == null && - validType) { + validType && validUrl) { long size = 0; try { size = Long.parseLong(attributes.getValue(ENC_LEN)); @@ -70,8 +73,8 @@ public class NSRSS20 extends Namespace { } catch (NumberFormatException e) { Log.d(TAG, "Length attribute could not be parsed."); } - state.getCurrentItem().setMedia( - new FeedMedia(state.getCurrentItem(), url, size, type)); + FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type); + state.getCurrentItem().setMedia(media); } } else if (IMAGE.equals(localName)) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java index 13aadf027..6251cc4a0 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java @@ -216,7 +216,7 @@ public abstract class PlaybackController { Intent serviceIntent = new Intent(activity, PlaybackService.class); serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); serviceIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, false); - serviceIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, false); + serviceIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, true); boolean fileExists = media.localFileAvailable(); boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream(); if (!fileExists && !lastIsStream && media instanceof FeedMedia) { diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml index 238169877..133a3ed6e 100644 --- a/core/src/main/res/values/arrays.xml +++ b/core/src/main/res/values/arrays.xml @@ -187,6 +187,7 @@ <item>@string/hide_not_queued_episodes_label</item> <item>@string/hide_downloaded_episodes_label</item> <item>@string/hide_not_downloaded_episodes_label</item> + <item>@string/hide_has_media_label</item> </string-array> <string-array name="episode_filter_values"> @@ -197,6 +198,7 @@ <item>not_queued</item> <item>downloaded</item> <item>not_downloaded</item> + <item>has_media</item> </string-array> <string-array name="image_cache_size_options"> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index c330756f1..8a92ab5b2 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -112,6 +112,8 @@ <string name="mark_all_read_confirmation_msg">Please confirm that you want to mark all episodes as being played.</string> <string name="mark_all_read_feed_confirmation_msg">Please confirm that you want to mark all episodes in this feed as being played.</string> <string name="mark_all_seen_label">Mark all as seen</string> + <string name="mark_all_seen_msg">Marked all Episodes as seen</string> + <string name="mark_all_seen_confirmation_msg">Please confirm that you want to mark all episodes as seen.</string> <string name="show_info_label">Show information</string> <string name="remove_feed_label">Remove Podcast</string> <string name="share_label">Share…</string> @@ -132,6 +134,7 @@ <string name="hide_not_queued_episodes_label">Not queued</string> <string name="hide_downloaded_episodes_label">Downloaded</string> <string name="hide_not_downloaded_episodes_label">Not downloaded</string> + <string name="hide_has_media_label">Has media</string> <string name="filtered_label">Filtered</string> <string name="refresh_failed_msg">{fa-exclamation-circle} Last Refresh failed</string> <string name="open_podcast">Open Podcast</string> @@ -367,10 +370,13 @@ <string name="pref_gpodnet_logout_toast">Logout was successful</string> <string name="pref_gpodnet_setlogin_information_title">Change login information</string> <string name="pref_gpodnet_setlogin_information_sum">Change the login information for your gpodder.net account.</string> - <string name="pref_gpodnet_sync_title">Sync now</string> - <string name="pref_gpodnet_sync_sum">Sync subscriptions and episode states with gpodder.net.</string> + <string name="pref_gpodnet_sync_changes_title">Sync changes now</string> + <string name="pref_gpodnet_sync_changes_sum">Sync subscription and episode state changes with gpodder.net.</string> + <string name="pref_gpodnet_full_sync_title">Full sync now</string> + <string name="pref_gpodnet_full_sync_sum">Sync all subscriptions and episode states with gpodder.net.</string> <string name="pref_gpodnet_sync_sum_last_sync_line">Last sync attempt: %1$s (%2$s)</string> <string name="pref_gpodnet_sync_started">Sync started</string> + <string name="pref_gpodnet_full_sync_started">Full sync started</string> <string name="pref_gpodnet_login_status"><![CDATA[Logged in as <i>%1$s</i> with device <i>%2$s</i>]]></string> <string name="pref_gpodnet_notifications_title">Show sync error notifications</string> <string name="pref_gpodnet_notifications_sum">This setting does not apply to authentication errors.</string> @@ -446,6 +452,7 @@ <string name="choose_file_from_filesystem">From local filesystem</string> <string name="choose_file_from_external_application">Use external application</string> <string name="opml_export_label">OPML export</string> + <string name="html_export_label">HTML export</string> <string name="exporting_label">Exporting…</string> <string name="export_error_label">Export error</string> <string name="opml_export_success_title">OPML Export successful.</string> @@ -588,6 +595,8 @@ <string name="selected_queued_label">Selected queued Episodes</string> <string name="not_queued_label">Not queued</string> <string name="selected_not_queued_label">Selected not queued Episodes</string> + <string name="has_media">Has media</string> + <string name="selected_has_media_label">Selected episodes with media</string> <!-- Sort --> <string name="sort_title_a_z">Title (A \u2192 Z)</string> |