Merge pull request #2158 from mfietz/feature/2154-export-html

Export subscriptions as HTML
This commit is contained in:
Martin Fietz 2016-10-30 12:51:21 +01:00 committed by GitHub
commit ff5b136351
22 changed files with 384 additions and 205 deletions

View File

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

View File

@ -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;
/**

View File

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

View File

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

View File

@ -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")
@ -60,6 +58,12 @@ public class PreferenceActivityGingerbread extends android.preference.Preference
super.onPause();
}
@Override
protected void onStop() {
preferenceController.onStop();
super.onStop();
}
@Override
protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
theme.applyStyle(UserPreferences.getTheme(), true);

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
@ -80,6 +88,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
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";
@ -97,32 +106,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
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 final PreferenceUI ui;
private CheckBoxPreference[] selectedNetworks;
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)) {
@ -130,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.
@ -144,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();
@ -179,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 &&
@ -440,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));
@ -464,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 &&

View File

@ -288,6 +288,9 @@
<Preference
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"/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package de.danoeh.antennapod.core.opml;
package de.danoeh.antennapod.core.export.opml;
import android.util.Log;

View File

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

View File

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

View File

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

View File

@ -451,6 +451,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&#8230;</string>
<string name="export_error_label">Export error</string>
<string name="opml_export_success_title">OPML Export successful.</string>