diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c03ff3a0a..2f944dfe6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -195,10 +195,6 @@ - - diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java deleted file mode 100644 index 1c61fc15e..000000000 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java +++ /dev/null @@ -1,143 +0,0 @@ -package de.danoeh.antennapod.activity; - -import android.content.Intent; -import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; -import android.util.SparseBooleanArray; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.ListView; - -import java.util.ArrayList; -import java.util.List; - -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.export.opml.OpmlElement; -import de.danoeh.antennapod.core.preferences.UserPreferences; - -/** - * Displays the feeds that the OPML-Importer has read and lets the user choose - * which feeds he wants to import. - */ -public class OpmlFeedChooserActivity extends AppCompatActivity { - 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; - private ArrayAdapter listAdapter; - - private MenuItem selectAll; - private MenuItem deselectAll; - - @Override - protected void onCreate(Bundle savedInstanceState) { - setTheme(UserPreferences.getTheme()); - super.onCreate(savedInstanceState); - - setContentView(R.layout.opml_selection); - butConfirm = findViewById(R.id.butConfirm); - butCancel = findViewById(R.id.butCancel); - feedlist = findViewById(R.id.feedlist); - - feedlist.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - listAdapter = new ArrayAdapter<>(this, - android.R.layout.simple_list_item_multiple_choice, - getTitleList()); - - feedlist.setAdapter(listAdapter); - feedlist.setOnItemClickListener((parent, view, position, id) -> { - SparseBooleanArray checked = feedlist.getCheckedItemPositions(); - int checkedCount = 0; - for (int i = 0; i < checked.size(); i++) { - if (checked.valueAt(i)) { - checkedCount++; - } - } - if(checkedCount == listAdapter.getCount()) { - selectAll.setVisible(false); - deselectAll.setVisible(true); - } else { - deselectAll.setVisible(false); - selectAll.setVisible(true); - } - }); - - butCancel.setOnClickListener(v -> { - setResult(RESULT_CANCELED); - finish(); - }); - - butConfirm.setOnClickListener(v -> { - Intent intent = new Intent(); - SparseBooleanArray checked = feedlist.getCheckedItemPositions(); - - int checkedCount = 0; - // Get number of checked items - for (int i = 0; i < checked.size(); i++) { - if (checked.valueAt(i)) { - checkedCount++; - } - } - int[] selection = new int[checkedCount]; - for (int i = 0, collected = 0; collected < checkedCount; i++) { - if (checked.valueAt(i)) { - selection[collected] = checked.keyAt(i); - collected++; - } - } - intent.putExtra(EXTRA_SELECTED_ITEMS, selection); - setResult(RESULT_OK, intent); - finish(); - }); - - } - - private List getTitleList() { - List result = new ArrayList<>(); - if (OpmlImportHolder.getReadElements() != null) { - for (OpmlElement element : OpmlImportHolder.getReadElements()) { - result.add(element.getText()); - } - } - return result; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.opml_selection_options, menu); - selectAll = menu.findItem(R.id.select_all_item); - deselectAll = menu.findItem(R.id.deselect_all_item); - deselectAll.setVisible(false); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - final int itemId = item.getItemId(); - if (itemId == R.id.select_all_item) { - selectAll.setVisible(false); - selectAllItems(true); - deselectAll.setVisible(true); - return true; - } else if (itemId == R.id.deselect_all_item) { - deselectAll.setVisible(false); - selectAllItems(false); - selectAll.setVisible(true); - return true; - } - return false; - } - - private void selectAllItems(boolean b) { - for (int i = 0; i < feedlist.getCount(); i++) { - feedlist.setItemChecked(i, b); - } - } - -} 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 d4e9ee5d9..2b8064270 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java @@ -7,17 +7,32 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.util.Log; +import android.util.SparseBooleanArray; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.OpmlFeedQueuer; -import de.danoeh.antennapod.asynctask.OpmlImportWorker; import de.danoeh.antennapod.core.export.opml.OpmlElement; +import de.danoeh.antennapod.core.export.opml.OpmlReader; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.storage.DownloadRequestException; +import de.danoeh.antennapod.core.storage.DownloadRequester; +import de.danoeh.antennapod.databinding.OpmlSelectionBinding; +import de.danoeh.antennapod.model.feed.Feed; +import io.reactivex.Completable; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; import org.apache.commons.io.ByteOrderMark; import org.apache.commons.io.input.BOMInputStream; import org.apache.commons.lang3.ArrayUtils; @@ -26,6 +41,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; +import java.util.List; /** * Activity for Opml Import. @@ -34,13 +50,73 @@ public class OpmlImportActivity extends AppCompatActivity { private static final String TAG = "OpmlImportBaseActivity"; private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5; @Nullable private Uri uri; + OpmlSelectionBinding viewBinding; + private ArrayAdapter listAdapter; + private MenuItem selectAll; + private MenuItem deselectAll; + private ArrayList readElements; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { setTheme(UserPreferences.getTheme()); super.onCreate(savedInstanceState); getSupportActionBar().setDisplayHomeAsUpEnabled(true); + viewBinding = OpmlSelectionBinding.inflate(getLayoutInflater()); + setContentView(viewBinding.getRoot()); + viewBinding.feedlist.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); + viewBinding.feedlist.setOnItemClickListener((parent, view, position, id) -> { + SparseBooleanArray checked = viewBinding.feedlist.getCheckedItemPositions(); + int checkedCount = 0; + for (int i = 0; i < checked.size(); i++) { + if (checked.valueAt(i)) { + checkedCount++; + } + } + if (checkedCount == listAdapter.getCount()) { + selectAll.setVisible(false); + deselectAll.setVisible(true); + } else { + deselectAll.setVisible(false); + selectAll.setVisible(true); + } + }); + viewBinding.butCancel.setOnClickListener(v -> { + setResult(RESULT_CANCELED); + finish(); + }); + viewBinding.butConfirm.setOnClickListener(v -> { + viewBinding.progressBar.setVisibility(View.VISIBLE); + Completable.fromAction(() -> { + DownloadRequester requester = DownloadRequester.getInstance(); + SparseBooleanArray checked = viewBinding.feedlist.getCheckedItemPositions(); + for (int i = 0; i < checked.size(); i++) { + if (!checked.valueAt(i)) { + continue; + } + OpmlElement element = readElements.get(checked.keyAt(i)); + Feed feed = new Feed(element.getXmlUrl(), null, element.getText()); + try { + requester.downloadFeed(getApplicationContext(), feed); + } catch (DownloadRequestException e) { + e.printStackTrace(); + } + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + () -> { + viewBinding.progressBar.setVisibility(View.GONE); + Intent intent = new Intent(OpmlImportActivity.this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finish(); + }, e -> { + viewBinding.progressBar.setVisibility(View.GONE); + Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); + }); + }); Uri uri = getIntent().getData(); if (uri != null && uri.toString().startsWith("/")) { @@ -54,39 +130,6 @@ public class OpmlImportActivity extends AppCompatActivity { importUri(uri); } - /** - * Handles the choices made by the user in the OpmlFeedChooserActivity and - * starts the OpmlFeedQueuer if necessary. - */ - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - Log.d(TAG, "Received result"); - if (resultCode == RESULT_CANCELED) { - Log.d(TAG, "Activity was cancelled"); - finish(); - } else { - int[] selected = data.getIntArrayExtra(OpmlFeedChooserActivity.EXTRA_SELECTED_ITEMS); - if (selected != null && selected.length > 0) { - OpmlFeedQueuer queuer = new OpmlFeedQueuer(this, selected) { - - @Override - protected void onPostExecute(Void result) { - super.onPostExecute(result); - Intent intent = new Intent(OpmlImportActivity.this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP - | Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } - - }; - queuer.executeAsync(); - } else { - Log.d(TAG, "No items were selected"); - } - } - } - void importUri(@Nullable Uri uri) { if (uri == null) { new AlertDialog.Builder(this) @@ -108,6 +151,52 @@ public class OpmlImportActivity extends AppCompatActivity { startImport(); } + private List getTitleList() { + List result = new ArrayList<>(); + if (readElements != null) { + for (OpmlElement element : readElements) { + result.add(element.getText()); + } + } + return result; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.opml_selection_options, menu); + selectAll = menu.findItem(R.id.select_all_item); + deselectAll = menu.findItem(R.id.deselect_all_item); + deselectAll.setVisible(false); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + final int itemId = item.getItemId(); + if (itemId == R.id.select_all_item) { + selectAll.setVisible(false); + selectAllItems(true); + deselectAll.setVisible(true); + return true; + } else if (itemId == R.id.deselect_all_item) { + deselectAll.setVisible(false); + selectAllItems(false); + selectAll.setVisible(true); + return true; + } else if (itemId == android.R.id.home) { + finish(); + } + return false; + } + + private void selectAllItems(boolean b) { + for (int i = 0; i < viewBinding.feedlist.getCount(); i++) { + viewBinding.feedlist.setItemChecked(i, b); + } + } + private void requestPermission() { String[] permissions = { android.Manifest.permission.READ_EXTERNAL_STORAGE }; ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_READ_EXTERNAL_STORAGE); @@ -132,37 +221,37 @@ public class OpmlImportActivity extends AppCompatActivity { /** Starts the import process. */ private void startImport() { - try { + viewBinding.progressBar.setVisibility(View.VISIBLE); + + Observable.fromCallable(() -> { InputStream opmlFileStream = getContentResolver().openInputStream(uri); BOMInputStream bomInputStream = new BOMInputStream(opmlFileStream); ByteOrderMark bom = bomInputStream.getBOM(); String charsetName = (bom == null) ? "UTF-8" : bom.getCharsetName(); Reader reader = new InputStreamReader(bomInputStream, charsetName); - - OpmlImportWorker importWorker = new OpmlImportWorker(this, reader) { - - @Override - protected void onPostExecute(ArrayList result) { - super.onPostExecute(result); - if (result != null) { - Log.d(TAG, "Parsing was successful"); - OpmlImportHolder.setReadElements(result); - startActivityForResult(new Intent( - OpmlImportActivity.this, - OpmlFeedChooserActivity.class), 0); - } else { - Log.d(TAG, "Parser error occurred"); - } - } - }; - importWorker.executeAsync(); - } catch (Exception e) { - Log.d(TAG, Log.getStackTraceString(e)); - String message = getString(R.string.opml_reader_error); - new AlertDialog.Builder(this) - .setMessage(message + " " + e.getMessage()) - .setPositiveButton(android.R.string.ok, null) - .show(); - } + OpmlReader opmlReader = new OpmlReader(); + ArrayList result = opmlReader.readDocument(reader); + reader.close(); + return result; + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + result -> { + viewBinding.progressBar.setVisibility(View.GONE); + Log.d(TAG, "Parsing was successful"); + readElements = result; + listAdapter = new ArrayAdapter<>(OpmlImportActivity.this, + android.R.layout.simple_list_item_multiple_choice, + getTitleList()); + viewBinding.feedlist.setAdapter(listAdapter); + }, e -> { + viewBinding.progressBar.setVisibility(View.GONE); + AlertDialog.Builder alert = new AlertDialog.Builder(this); + alert.setTitle(R.string.error_label); + alert.setMessage(getString(R.string.opml_reader_error) + e.getMessage()); + alert.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss()); + alert.create().show(); + }); } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java deleted file mode 100644 index dc5570dc0..000000000 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.danoeh.antennapod.activity; - -import java.util.ArrayList; - -import de.danoeh.antennapod.core.export.opml.OpmlElement; - -/** - * Hold infos gathered by Ompl-Import - *

- * Created with IntelliJ IDEA. - * User: ligi - * Date: 1/23/13 - * Time: 2:15 PM - */ -public class OpmlImportHolder { - - private OpmlImportHolder(){} - - private static ArrayList readElements; - - public static ArrayList getReadElements() { - return readElements; - } - - public static void setReadElements(ArrayList _readElements) { - readElements = _readElements; - } - - -} - diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java deleted file mode 100644 index a80e3d59b..000000000 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java +++ /dev/null @@ -1,62 +0,0 @@ -package de.danoeh.antennapod.asynctask; - -import android.app.ProgressDialog; -import android.content.Context; -import android.os.AsyncTask; - -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.model.feed.Feed; -import de.danoeh.antennapod.core.storage.DownloadRequestException; -import de.danoeh.antennapod.core.storage.DownloadRequester; - -/** Queues items for download in the background. */ -public class OpmlFeedQueuer extends AsyncTask { - private final Context context; - private ProgressDialog progDialog; - private final int[] selection; - - public OpmlFeedQueuer(Context context, int[] selection) { - super(); - this.context = context; - this.selection = Arrays.copyOf(selection, selection.length); - } - - @Override - protected void onPostExecute(Void result) { - progDialog.dismiss(); - } - - @Override - protected void onPreExecute() { - progDialog = new ProgressDialog(context); - progDialog.setMessage(context.getString(R.string.processing_label)); - progDialog.setCancelable(false); - progDialog.setIndeterminate(true); - progDialog.show(); - } - - @Override - protected Void doInBackground(Void... params) { - DownloadRequester requester = DownloadRequester.getInstance(); - for (int selected : selection) { - OpmlElement element = OpmlImportHolder.getReadElements().get(selected); - Feed feed = new Feed(element.getXmlUrl(), null, - element.getText()); - try { - requester.downloadFeed(context.getApplicationContext(), feed); - } catch (DownloadRequestException e) { - e.printStackTrace(); - } - } - return null; - } - - public void executeAsync() { - executeOnExecutor(THREAD_POOL_EXECUTOR); - } - -} diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java deleted file mode 100644 index e037eb392..000000000 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java +++ /dev/null @@ -1,93 +0,0 @@ -package de.danoeh.antennapod.asynctask; - -import android.app.ProgressDialog; -import android.content.Context; -import android.os.AsyncTask; -import androidx.appcompat.app.AlertDialog; -import android.util.Log; - -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; - -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.core.export.opml.OpmlElement; -import de.danoeh.antennapod.core.export.opml.OpmlReader; - -public class OpmlImportWorker extends AsyncTask> { - private static final String TAG = "OpmlImportWorker"; - - private final Context context; - private Exception exception; - private ProgressDialog progDialog; - - private final Reader reader; - - public OpmlImportWorker(Context context, Reader reader) { - super(); - this.context = context; - this.reader = reader; - } - - @Override - protected ArrayList doInBackground(Void... params) { - Log.d(TAG, "Starting background work"); - - if (reader == null) { - return null; - } - - OpmlReader opmlReader = new OpmlReader(); - try { - ArrayList result = opmlReader.readDocument(reader); - reader.close(); - return result; - } catch (XmlPullParserException e) { - e.printStackTrace(); - exception = e; - return null; - } catch (IOException e) { - e.printStackTrace(); - exception = e; - return null; - } - - } - - @Override - protected void onPostExecute(ArrayList result) { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - progDialog.dismiss(); - if (exception != null) { - Log.d(TAG, "An error occurred while trying to parse the opml document"); - AlertDialog.Builder alert = new AlertDialog.Builder(context); - alert.setTitle(R.string.error_label); - alert.setMessage(context.getString(R.string.opml_reader_error) - + exception.getMessage()); - alert.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss()); - alert.create().show(); - } - } - - @Override - protected void onPreExecute() { - progDialog = new ProgressDialog(context); - progDialog.setMessage(context.getString(R.string.please_wait)); - progDialog.setIndeterminate(true); - progDialog.setCancelable(false); - progDialog.show(); - } - - public void executeAsync() { - executeOnExecutor(THREAD_POOL_EXECUTOR); - } - -} diff --git a/app/src/main/res/layout/opml_selection.xml b/app/src/main/res/layout/opml_selection.xml index 1f1d72d76..735c7f87e 100644 --- a/app/src/main/res/layout/opml_selection.xml +++ b/app/src/main/res/layout/opml_selection.xml @@ -1,39 +1,44 @@ + 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">