"Add feed" facelift, OPML import with better explanations and usage of external apps

This commit is contained in:
Martin Fietz 2015-03-30 12:18:16 +02:00
parent f104bc5b9b
commit 680c9db075
5 changed files with 268 additions and 198 deletions

View File

@ -1,7 +1,9 @@
package de.danoeh.antennapod.activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
@ -10,23 +12,31 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.LangUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
import java.io.*;
/**
* Lets the user start the OPML-import process from a path
*/
public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
private static final String TAG = "OpmlImportFromPathActivity";
private TextView txtvPath;
private Button butStart;
private String importPath;
private static final int CHOOSE_OPML_FILE = 1;
private Intent intentPickAction;
private Intent intentGetContentAction;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -36,47 +46,74 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.opml_import);
txtvPath = (TextView) findViewById(R.id.txtvPath);
butStart = (Button) findViewById(R.id.butStartImport);
final TextView txtvHeaderExplanation1 = (TextView) findViewById(R.id.txtvHeadingExplanation1);
final TextView txtvExplanation1 = (TextView) findViewById(R.id.txtvExplanation1);
final TextView txtvHeaderExplanation2 = (TextView) findViewById(R.id.txtvHeadingExplanation2);
final TextView txtvExplanation2 = (TextView) findViewById(R.id.txtvExplanation2);
final TextView txtvHeaderExplanation3 = (TextView) findViewById(R.id.txtvHeadingExplanation3);
butStart.setOnClickListener(new OnClickListener() {
Button butChooseFilesystem = (Button) findViewById(R.id.butChooseFileFromFilesystem);
butChooseFilesystem.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
checkFolderForFiles();
chooseFileFromFilesystem();
}
});
Button butChooseExternal = (Button) findViewById(R.id.butChooseFileFromExternal);
butChooseExternal.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
chooseFileFromExternal();
}
});
int nextOption = 1;
intentPickAction = new Intent(Intent.ACTION_PICK);
intentPickAction.setData(Uri.parse("file://"));
List<ResolveInfo> intentActivities = getPackageManager()
.queryIntentActivities(intentPickAction, CHOOSE_OPML_FILE);
if(intentActivities.size() == 0) {
intentPickAction.setData(null);
intentActivities = getPackageManager()
.queryIntentActivities(intentPickAction, CHOOSE_OPML_FILE);
if(intentActivities.size() == 0) {
txtvHeaderExplanation1.setVisibility(View.GONE);
txtvExplanation1.setVisibility(View.GONE);
findViewById(R.id.divider1).setVisibility(View.GONE);
butChooseFilesystem.setVisibility(View.GONE);
}
}
if(txtvExplanation1.getVisibility() == View.VISIBLE) {
txtvHeaderExplanation1.setText("Option " + nextOption);
nextOption++;
}
intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
intentGetContentAction.setType("*/*");
intentActivities = getPackageManager()
.queryIntentActivities(intentGetContentAction, CHOOSE_OPML_FILE);
if(intentActivities.size() == 0) {
txtvHeaderExplanation2.setVisibility(View.GONE);
txtvExplanation2.setVisibility(View.GONE);
findViewById(R.id.divider2).setVisibility(View.GONE);
butChooseExternal.setVisibility(View.GONE);
} else {
txtvHeaderExplanation2.setText("Option " + nextOption);
nextOption++;
}
txtvHeaderExplanation3.setText("Option " + nextOption);
}
@Override
protected void onResume() {
super.onResume();
StorageUtils.checkStorageAvailability(this);
setImportPath();
}
/**
* Sets the importPath variable and makes txtvPath display the import
* directory.
*/
private void setImportPath() {
File importDir = UserPreferences.getDataFolder(this, UserPreferences.IMPORT_DIR);
boolean success = true;
if (!importDir.exists()) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Import directory doesn't exist. Creating...");
success = importDir.mkdir();
if (!success) {
Log.e(TAG, "Could not create directory");
}
}
if (success) {
txtvPath.setText(importDir.toString());
importPath = importDir.toString();
} else {
txtvPath.setText(R.string.opml_directory_error);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
@ -95,32 +132,6 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
}
}
/**
* Looks at the contents of the import directory and decides what to do. If
* more than one file is in the directory, a dialog will be created to let
* the user choose which item to import
*/
private void checkFolderForFiles() {
File dir = new File(importPath);
if (dir.isDirectory()) {
File[] fileList = dir.listFiles();
if (fileList.length == 1) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Found one file, choosing that one.");
startImport(fileList[0]);
} else if (fileList.length > 1) {
Log.w(TAG, "Import directory contains more than one file.");
askForFile(dir);
} else {
Log.e(TAG, "Import directory is empty");
Toast toast = Toast
.makeText(this, R.string.opml_import_error_dir_empty,
Toast.LENGTH_LONG);
toast.show();
}
}
}
private void startImport(File file) {
Reader mReader = null;
try {
@ -134,38 +145,36 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
}
}
/**
* Asks the user to choose from a list of files in a directory and returns
* his choice.
/*
* Creates an implicit intent to launch a file manager which lets
* the user choose a specific OPML-file to import from.
*/
private void askForFile(File dir) {
final File[] fileList = dir.listFiles();
String[] fileNames = dir.list();
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle(R.string.choose_file_to_import_label);
dialog.setNeutralButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Dialog was cancelled");
dialog.dismiss();
}
});
dialog.setItems(fileNames, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (BuildConfig.DEBUG)
Log.d(TAG, "File at index " + which + " was chosen");
dialog.dismiss();
startImport(fileList[which]);
}
});
dialog.create().show();
private void chooseFileFromFilesystem() {
try {
startActivityForResult(intentPickAction, CHOOSE_OPML_FILE);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "No activity found. Should never happen...");
}
}
private void chooseFileFromExternal() {
try {
startActivityForResult(intentGetContentAction, CHOOSE_OPML_FILE);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "No activity found. Should never happen...");
}
}
/**
* Gets the path of the file chosen with chooseFileToImport()
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == CHOOSE_OPML_FILE) {
String filename = data.getData().getPath();
startImport(new File(filename));
}
}
}

View File

@ -1,107 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<ScrollView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:scrollbars="vertical">
android:paddingTop="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingBottom="8dp"
android:orientation="vertical">
<RelativeLayout
<TextView
android:id="@+id/txtvFeedurl"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/txtvfeedurl_label"/>
<TextView
android:id="@+id/txtvFeedurl"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/txtvfeedurl_label"/>
<EditText
android:id="@+id/etxtFeedurl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:hint="@string/etxtFeedurlHint"
android:inputType="textUri"/>
<EditText
android:id="@+id/etxtFeedurl"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/txtvFeedurl"
android:layout_margin="8dp"
android:hint="@string/etxtFeedurlHint"
android:inputType="textUri"/>
<Button
android:id="@+id/butConfirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/confirm_label"/>
<Button
android:id="@+id/butConfirm"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/etxtFeedurl"
android:layout_margin="8dp"
android:text="@string/confirm_label"/>
<View
android:id="@+id/divider1"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="16dp"
android:background="?android:attr/listDivider"/>
<TextView
android:id="@+id/txtvPodcastDirectories"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/butConfirm"
android:layout_margin="8dp"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/podcastdirectories_label"/>
<TextView
android:id="@+id/txtvPodcastDirectories"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/divider1"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/podcastdirectories_label"/>
<TextView
android:id="@+id/txtvPodcastDirectoriesDescr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/podcastdirectories_descr"
android:textSize="@dimen/text_size_medium"
android:layout_below="@id/txtvPodcastDirectories"
android:layout_margin="8dp"/>
<TextView
android:id="@+id/txtvPodcastDirectoriesDescr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/podcastdirectories_descr"
android:textSize="@dimen/text_size_medium"
android:layout_marginTop="4dp"/>
<Button
android:id="@+id/butBrowseGpoddernet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/txtvPodcastDirectoriesDescr"
android:layout_margin="8dp"
android:text="@string/browse_gpoddernet_label"/>
<Button
android:id="@+id/butBrowseGpoddernet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/browse_gpoddernet_label"/>
<Button
android:id="@+id/butSearchItunes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/butBrowseGpoddernet"
android:layout_margin="8dp"
android:text="@string/search_itunes_label"/>
<Button
android:id="@+id/butSearchItunes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/search_itunes_label"/>
<TextView
android:id="@+id/txtvOpmlImport"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/butSearchItunes"
android:layout_margin="8dp"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/opml_import_label"/>
<View
android:id="@+id/divider2"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="16dp"
android:background="?android:attr/listDivider"/>
<TextView
android:id="@+id/txtvOpmlImportExpl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/txtvOpmlImport"
android:layout_margin="8dp"
android:textSize="@dimen/text_size_medium"
android:text="@string/opml_import_txtv_button_lable"/>
<TextView
android:id="@+id/txtvOpmlImport"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/opml_import_label"/>
<Button
android:id="@+id/butOpmlImport"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/txtvOpmlImportExpl"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:text="@string/opml_import_label"/>
</RelativeLayout>
</ScrollView>
<TextView
android:id="@+id/txtvOpmlImportExpl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textSize="@dimen/text_size_medium"
android:text="@string/opml_import_txtv_button_lable"/>
</RelativeLayout>
<Button
android:id="@+id/butOpmlImport"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/opml_import_label"/>
</LinearLayout>
</ScrollView>

View File

@ -1,32 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingBottom="8dp"
tools:background="@android:color/darker_gray">
<TextView
android:id="@+id/txtvHeadingExplanation1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/opml_import_explanation"
tools:background="@android:color/holo_green_dark" />
style="@style/AntennaPod.TextView.Heading"
android:text="@string/txtvfeedurl_label"/>
<TextView
android:id="@+id/txtvPath"
android:id="@+id/txtvExplanation1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
tools:text="Path"
android:text="@string/opml_import_explanation_1"
android:textSize="@dimen/text_size_medium"
android:layout_marginTop="4dp"
tools:background="@android:color/holo_green_dark" />
<Button
android:id="@+id/butStartImport"
android:layout_width="wrap_content"
android:id="@+id/butChooseFileFromFilesystem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="8dp"
android:text="@string/start_import_label" />
android:layout_marginTop="8dp"
android:text="@string/choose_file_from_filesystem" />
<View
android:id="@+id/divider1"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_margin="16dp"
android:background="?android:attr/listDivider"/>
<TextView
android:id="@+id/txtvHeadingExplanation2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/txtvfeedurl_label"/>
<TextView
android:id="@+id/txtvExplanation2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/opml_import_explanation_2"
android:textSize="@dimen/text_size_medium"
android:layout_marginTop="4dp"
tools:background="@android:color/holo_green_dark" />
<Button
android:id="@+id/butChooseFileFromExternal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:text="@string/choose_file_from_external_application" />
<View
android:id="@+id/divider2"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_margin="16dp"
android:background="?android:attr/listDivider"/>
<TextView
android:id="@+id/txtvHeadingExplanation3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/AntennaPod.TextView.Heading"
android:text="@string/txtvfeedurl_label"/>
<TextView
android:id="@+id/txtvExplanation3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/opml_import_explanation_3"
android:textSize="@dimen/text_size_medium"
android:layout_marginTop="4dp"
tools:background="@android:color/holo_green_dark" />
</LinearLayout>

View File

@ -71,7 +71,7 @@
<!-- 'Add Feed' Activity labels -->
<string name="feedurl_label">Feed URL</string>
<string name="etxtFeedurlHint">URL of feed or website</string>
<string name="etxtFeedurlHint">www.example.com/feed</string>
<string name="txtvfeedurl_label">Add Podcast by URL</string>
<string name="podcastdirectories_label">Find podcast in directory</string>
<string name="podcastdirectories_descr">You can search for new podcasts by name, category or popularity in the gpodder.net directory, or search the iTunes store.</string>
@ -293,8 +293,9 @@
<!-- OPML import and export -->
<string name="opml_import_txtv_button_lable">OPML files allow you to move your podcasts from one podcatcher to another.</string>
<string name="opml_import_explanation">To import an OPML file, you have to place it in the following directory and press the button below to start the import process. </string>
<string name="start_import_label">Start import</string>
<string name="opml_import_explanation_1">Choose a specific file path from the local filesystem.</string>
<string name="opml_import_explanation_2">Use an external applications like Dropbox, Google Drive or your favourite file manager to open an OPML file.</string>
<string name="opml_import_explanation_3">Many applications like Google Mail, Dropbox, Google Drive and most file managers can <i>open</i> OPML files <i>with</i> AntennaPod.</string> <string name="start_import_label">Start import</string>
<string name="opml_import_label">OPML import</string>
<string name="opml_directory_error">ERROR!</string>
<string name="reading_opml_label">Reading OPML file</string>
@ -302,11 +303,12 @@
<string name="opml_import_error_dir_empty">The import directory is empty.</string>
<string name="select_all_label">Select all</string>
<string name="deselect_all_label">Deselect all</string>
<string name="choose_file_to_import_label">Choose file to import</string>
<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="exporting_label">Exporting...</string>
<string name="export_error_label">Export error</string>
<string name="opml_export_success_title">Opml export successful.</string>
<string name="opml_export_success_title">OPML export successful.</string>
<string name="opml_export_success_sum">The .opml file was written to:\u0020</string>
<!-- Sleep timer -->

View File

@ -219,7 +219,6 @@
<style name="AntennaPod.TextView.Heading" parent="@android:style/TextAppearance.Medium">
<item name="android:textSize">@dimen/text_size_large</item>
<item name="android:textStyle">italic</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>