summaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java183
4 files changed, 111 insertions, 212 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
index 3f1c17cdc..caafe989d 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
@@ -26,14 +26,14 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.export.opml.OpmlElement;
-import de.danoeh.antennapod.core.export.opml.OpmlReader;
import de.danoeh.antennapod.core.preferences.ThemeSwitcher;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.databinding.OpmlSelectionBinding;
import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.storage.importexport.OpmlElement;
+import de.danoeh.antennapod.storage.importexport.OpmlReader;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java
deleted file mode 100644
index 8acfcb58f..000000000
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.danoeh.antennapod.asynctask;
-
-import android.content.Context;
-import android.net.Uri;
-import androidx.annotation.NonNull;
-import androidx.documentfile.provider.DocumentFile;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
-
-import de.danoeh.antennapod.core.export.ExportWriter;
-import de.danoeh.antennapod.core.storage.DBReader;
-import io.reactivex.Observable;
-
-/**
- * Writes an OPML file into the user selected export directory in the background.
- */
-public class DocumentFileExportWorker {
-
- private final @NonNull ExportWriter exportWriter;
- private @NonNull Context context;
- private @NonNull Uri outputFileUri;
-
- public DocumentFileExportWorker(@NonNull ExportWriter exportWriter, @NonNull Context context, @NonNull Uri outputFileUri) {
- this.exportWriter = exportWriter;
- this.context = context;
- this.outputFileUri = outputFileUri;
- }
-
- public Observable<DocumentFile> exportObservable() {
- DocumentFile output = DocumentFile.fromSingleUri(context, outputFileUri);
- return Observable.create(subscriber -> {
- OutputStream outputStream = null;
- OutputStreamWriter writer = null;
- try {
- Uri uri = output.getUri();
- outputStream = context.getContentResolver().openOutputStream(uri, "wt");
- if (outputStream == null) {
- throw new IOException();
- }
- writer = new OutputStreamWriter(outputStream, Charset.forName("UTF-8"));
- exportWriter.writeDocument(DBReader.getFeedList(), writer, context);
- subscriber.onNext(output);
- } catch (IOException e) {
- subscriber.onError(e);
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- subscriber.onError(e);
- }
- }
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException e) {
- subscriber.onError(e);
- }
- }
- subscriber.onComplete();
- }
- });
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
deleted file mode 100644
index 97a5f157b..000000000
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.danoeh.antennapod.asynctask;
-
-import android.content.Context;
-import androidx.annotation.NonNull;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
-
-import de.danoeh.antennapod.core.export.ExportWriter;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import io.reactivex.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 final @NonNull ExportWriter exportWriter;
- private final @NonNull File output;
- private final Context context;
-
- public ExportWorker(@NonNull ExportWriter exportWriter, Context context) {
- this(exportWriter, new File(UserPreferences.getDataFolder(EXPORT_DIR),
- DEFAULT_OUTPUT_NAME + "." + exportWriter.fileExtension()), context);
- }
-
- private ExportWorker(@NonNull ExportWriter exportWriter, @NonNull File output, Context context) {
- this.exportWriter = exportWriter;
- this.output = output;
- this.context = context;
- }
-
- public Observable<File> exportObservable() {
- if (output.exists()) {
- boolean success = output.delete();
- Log.w(TAG, "Overwriting previously exported file: " + success);
- }
- return Observable.create(subscriber -> {
- OutputStreamWriter writer = null;
- try {
- writer = new OutputStreamWriter(new FileOutputStream(output), Charset.forName("UTF-8"));
- exportWriter.writeDocument(DBReader.getFeedList(), writer, context);
- subscriber.onNext(output);
- } catch (IOException e) {
- subscriber.onError(e);
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- subscriber.onError(e);
- }
- }
- subscriber.onComplete();
- }
- });
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
index 71ba326dd..9191825aa 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
@@ -16,6 +16,7 @@ import androidx.activity.result.contract.ActivityResultContracts.GetContent;
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
+import androidx.documentfile.provider.DocumentFile;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import androidx.core.app.ShareCompat;
import androidx.core.content.FileProvider;
@@ -25,13 +26,15 @@ import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OpmlImportActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.asynctask.DocumentFileExportWorker;
-import de.danoeh.antennapod.asynctask.ExportWorker;
-import de.danoeh.antennapod.core.export.ExportWriter;
-import de.danoeh.antennapod.core.export.favorites.FavoritesWriter;
-import de.danoeh.antennapod.core.export.html.HtmlWriter;
-import de.danoeh.antennapod.core.export.opml.OpmlWriter;
-import de.danoeh.antennapod.core.storage.DatabaseExporter;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.model.feed.FeedItemFilter;
+import de.danoeh.antennapod.model.feed.SortOrder;
+import de.danoeh.antennapod.storage.importexport.DatabaseExporter;
+import de.danoeh.antennapod.storage.importexport.FavoritesWriter;
+import de.danoeh.antennapod.storage.importexport.HtmlWriter;
+import de.danoeh.antennapod.storage.importexport.OpmlWriter;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -39,8 +42,14 @@ import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
@@ -57,18 +66,29 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
private static final String CONTENT_TYPE_HTML = "text/html";
private static final String DEFAULT_FAVORITES_OUTPUT_NAME = "antennapod-favorites-%s.html";
private static final String DATABASE_EXPORT_FILENAME = "AntennaPodBackup-%s.db";
+
private final ActivityResultLauncher<Intent> chooseOpmlExportPathLauncher =
- registerForActivityResult(new StartActivityForResult(), this::chooseOpmlExportPathResult);
+ registerForActivityResult(new StartActivityForResult(),
+ result -> exportToDocument(result, Export.OPML));
private final ActivityResultLauncher<Intent> chooseHtmlExportPathLauncher =
- registerForActivityResult(new StartActivityForResult(), this::chooseHtmlExportPathResult);
+ registerForActivityResult(new StartActivityForResult(),
+ result -> exportToDocument(result, Export.HTML));
private final ActivityResultLauncher<Intent> chooseFavoritesExportPathLauncher =
- registerForActivityResult(new StartActivityForResult(), this::chooseFavoritesExportPathResult);
+ registerForActivityResult(new StartActivityForResult(),
+ result -> exportToDocument(result, Export.FAVORITES));
private final ActivityResultLauncher<Intent> restoreDatabaseLauncher =
registerForActivityResult(new StartActivityForResult(), this::restoreDatabaseResult);
private final ActivityResultLauncher<String> backupDatabaseLauncher =
registerForActivityResult(new BackupDatabase(), this::backupDatabaseResult);
private final ActivityResultLauncher<String> chooseOpmlImportPathLauncher =
- registerForActivityResult(new GetContent(), this::chooseOpmlImportPathResult);
+ registerForActivityResult(new GetContent(), uri -> {
+ if (uri != null) {
+ final Intent intent = new Intent(getContext(), OpmlImportActivity.class);
+ intent.setData(uri);
+ startActivity(intent);
+ }
+ });
+
private Disposable disposable;
private ProgressDialog progressDialog;
@@ -95,20 +115,16 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
}
}
- private String dateStampFilename(String fname) {
- return String.format(fname, new SimpleDateFormat("yyyy-MM-dd", Locale.US).format(new Date()));
- }
-
private void setupStorageScreen() {
findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
preference -> {
- openExportPathPicker(Export.OPML, chooseOpmlExportPathLauncher, new OpmlWriter());
+ openExportPathPicker(Export.OPML, chooseOpmlExportPathLauncher);
return true;
}
);
findPreference(PREF_HTML_EXPORT).setOnPreferenceClickListener(
preference -> {
- openExportPathPicker(Export.HTML, chooseHtmlExportPathLauncher, new HtmlWriter());
+ openExportPathPicker(Export.HTML, chooseHtmlExportPathLauncher);
return true;
});
findPreference(PREF_OPML_IMPORT).setOnPreferenceClickListener(
@@ -132,32 +148,13 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
});
findPreference(PREF_FAVORITE_EXPORT).setOnPreferenceClickListener(
preference -> {
- openExportPathPicker(Export.FAVORITES, chooseFavoritesExportPathLauncher, new FavoritesWriter());
+ openExportPathPicker(Export.FAVORITES, chooseFavoritesExportPathLauncher);
return true;
});
}
- private void exportWithWriter(ExportWriter exportWriter, Uri uri, Export exportType) {
- Context context = getActivity();
- progressDialog.show();
- if (uri == null) {
- Observable<File> observable = new ExportWorker(exportWriter, getContext()).exportObservable();
- disposable = observable.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(output -> {
- Uri fileUri = FileProvider.getUriForFile(context.getApplicationContext(),
- context.getString(R.string.provider_authority), output);
- showExportSuccessSnackbar(fileUri, exportType.contentType);
- }, this::showExportErrorDialog, progressDialog::dismiss);
- } else {
- DocumentFileExportWorker worker = new DocumentFileExportWorker(exportWriter, context, uri);
- disposable = worker.exportObservable()
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(output ->
- showExportSuccessSnackbar(output.getUri(), exportType.contentType),
- this::showExportErrorDialog, progressDialog::dismiss);
- }
+ private String dateStampFilename(String fname) {
+ return String.format(fname, new SimpleDateFormat("yyyy-MM-dd", Locale.US).format(new Date()));
}
private void exportDatabase() {
@@ -211,30 +208,6 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
alert.show();
}
- private void chooseOpmlExportPathResult(final ActivityResult result) {
- if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
- return;
- }
- final Uri uri = result.getData().getData();
- exportWithWriter(new OpmlWriter(), uri, Export.OPML);
- }
-
- private void chooseHtmlExportPathResult(final ActivityResult result) {
- if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
- return;
- }
- final Uri uri = result.getData().getData();
- exportWithWriter(new HtmlWriter(), uri, Export.HTML);
- }
-
- private void chooseFavoritesExportPathResult(final ActivityResult result) {
- if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
- return;
- }
- final Uri uri = result.getData().getData();
- exportWithWriter(new FavoritesWriter(), uri, Export.FAVORITES);
- }
-
private void restoreDatabaseResult(final ActivityResult result) {
if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
return;
@@ -264,16 +237,7 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
}, this::showExportErrorDialog);
}
- private void chooseOpmlImportPathResult(final Uri uri) {
- if (uri == null) {
- return;
- }
- final Intent intent = new Intent(getContext(), OpmlImportActivity.class);
- intent.setData(uri);
- startActivity(intent);
- }
-
- private void openExportPathPicker(Export exportType, ActivityResultLauncher<Intent> result, ExportWriter writer) {
+ private void openExportPathPicker(Export exportType, ActivityResultLauncher<Intent> result) {
String title = dateStampFilename(exportType.outputNameTemplate);
Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
@@ -292,7 +256,78 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
// If we are using a SDK lower than API 21 or the implicit intent failed
// fallback to the legacy export process
- exportWithWriter(writer, null, exportType);
+ File output = new File(UserPreferences.getDataFolder("export/"), title);
+ exportToFile(exportType, output);
+ }
+
+ private void exportToFile(Export exportType, File output) {
+ progressDialog.show();
+ disposable = Observable.create(
+ subscriber -> {
+ if (output.exists()) {
+ boolean success = output.delete();
+ Log.w(TAG, "Overwriting previously exported file: " + success);
+ }
+ try (FileOutputStream fileOutputStream = new FileOutputStream(output)) {
+ writeToStream(fileOutputStream, exportType);
+ subscriber.onNext(output);
+ } catch (IOException e) {
+ subscriber.onError(e);
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(outputFile -> {
+ progressDialog.dismiss();
+ Uri fileUri = FileProvider.getUriForFile(getActivity().getApplicationContext(),
+ getString(R.string.provider_authority), output);
+ showExportSuccessSnackbar(fileUri, exportType.contentType);
+ }, this::showExportErrorDialog, progressDialog::dismiss);
+ }
+
+ private void exportToDocument(final ActivityResult result, Export exportType) {
+ if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
+ return;
+ }
+ progressDialog.show();
+ DocumentFile output = DocumentFile.fromSingleUri(getContext(), result.getData().getData());
+ disposable = Observable.create(
+ subscriber -> {
+ try (OutputStream outputStream = getContext().getContentResolver()
+ .openOutputStream(output.getUri(), "wt")) {
+ writeToStream(outputStream, exportType);
+ subscriber.onNext(output);
+ } catch (IOException e) {
+ subscriber.onError(e);
+ }
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(ignore -> {
+ progressDialog.dismiss();
+ showExportSuccessSnackbar(output.getUri(), exportType.contentType);
+ }, this::showExportErrorDialog, progressDialog::dismiss);
+ }
+
+ private void writeToStream(OutputStream outputStream, Export type) throws IOException {
+ try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, Charset.forName("UTF-8"))) {
+ switch (type) {
+ case HTML:
+ HtmlWriter.writeDocument(DBReader.getFeedList(), writer, getContext());
+ break;
+ case OPML:
+ OpmlWriter.writeDocument(DBReader.getFeedList(), writer);
+ break;
+ case FAVORITES:
+ List<FeedItem> allFavorites = DBReader.getEpisodes(0, Integer.MAX_VALUE,
+ new FeedItemFilter(FeedItemFilter.IS_FAVORITE), SortOrder.DATE_NEW_OLD);
+ FavoritesWriter.writeDocument(allFavorites, writer, getContext());
+ break;
+ default:
+ showExportErrorDialog(new Exception("Invalid export type"));
+ break;
+ }
+ }
}
private static class BackupDatabase extends ActivityResultContracts.CreateDocument {