Removed our re-implementation of 'Optimal' and used the RxJava equivalent instead
This commit is contained in:
parent
d444e8d23e
commit
e59767890e
|
@ -16,6 +16,7 @@ import android.widget.AdapterView;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
@ -51,7 +52,6 @@ import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeExceptio
|
||||||
import de.danoeh.antennapod.core.util.DownloadError;
|
import de.danoeh.antennapod.core.util.DownloadError;
|
||||||
import de.danoeh.antennapod.core.util.FileNameGenerator;
|
import de.danoeh.antennapod.core.util.FileNameGenerator;
|
||||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||||
import de.danoeh.antennapod.core.util.Optional;
|
|
||||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||||
import de.danoeh.antennapod.core.util.URLChecker;
|
import de.danoeh.antennapod.core.util.URLChecker;
|
||||||
import de.danoeh.antennapod.core.util.playback.RemoteMedia;
|
import de.danoeh.antennapod.core.util.playback.RemoteMedia;
|
||||||
|
@ -60,9 +60,11 @@ import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
|
||||||
import de.danoeh.antennapod.databinding.OnlinefeedviewActivityBinding;
|
import de.danoeh.antennapod.databinding.OnlinefeedviewActivityBinding;
|
||||||
import de.danoeh.antennapod.dialog.AuthenticationDialog;
|
import de.danoeh.antennapod.dialog.AuthenticationDialog;
|
||||||
import de.danoeh.antennapod.discovery.PodcastSearcherRegistry;
|
import de.danoeh.antennapod.discovery.PodcastSearcherRegistry;
|
||||||
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
|
import io.reactivex.observers.DisposableMaybeObserver;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
@ -321,34 +323,48 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Parsing feed");
|
Log.d(TAG, "Parsing feed");
|
||||||
|
|
||||||
parser = Observable.fromCallable(this::doParseFeed)
|
parser = Maybe.fromCallable(this::doParseFeed)
|
||||||
.subscribeOn(Schedulers.computation())
|
.subscribeOn(Schedulers.computation())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(optionalResult -> {
|
.subscribeWith(new DisposableMaybeObserver<FeedHandlerResult>() {
|
||||||
if(optionalResult.isPresent()) {
|
@Override
|
||||||
FeedHandlerResult result = optionalResult.get();
|
public void onSuccess(@NonNull FeedHandlerResult result) {
|
||||||
beforeShowFeedInformation(result.feed);
|
beforeShowFeedInformation(result.feed);
|
||||||
showFeedInformation(result.feed, result.alternateFeedUrls);
|
showFeedInformation(result.feed, result.alternateFeedUrls);
|
||||||
}
|
}
|
||||||
}, error -> {
|
|
||||||
String errorMsg = DownloadError.ERROR_PARSER_EXCEPTION.getErrorString(
|
@Override
|
||||||
OnlineFeedViewActivity.this) + " (" + error.getMessage() + ")";
|
public void onComplete() {
|
||||||
showErrorDialog(errorMsg);
|
// Ignore null result: We showed the discovery dialog.
|
||||||
Log.d(TAG, "Feed parser exception: " + Log.getStackTraceString(error));
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(@NonNull Throwable error) {
|
||||||
|
String errorMsg = DownloadError.ERROR_PARSER_EXCEPTION.getErrorString(
|
||||||
|
OnlineFeedViewActivity.this) + " (" + error.getMessage() + ")";
|
||||||
|
showErrorDialog(errorMsg);
|
||||||
|
Log.d(TAG, "Feed parser exception: " + Log.getStackTraceString(error));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
/**
|
||||||
private Optional<FeedHandlerResult> doParseFeed() throws Exception {
|
* Try to parse the feed.
|
||||||
|
* @return The FeedHandlerResult if successful.
|
||||||
|
* Null if unsuccessful but we started another attempt.
|
||||||
|
* @throws Exception If unsuccessful but we do not know a resolution.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private FeedHandlerResult doParseFeed() throws Exception {
|
||||||
FeedHandler handler = new FeedHandler();
|
FeedHandler handler = new FeedHandler();
|
||||||
try {
|
try {
|
||||||
return Optional.of(handler.parseFeed(feed));
|
return handler.parseFeed(feed);
|
||||||
} catch (UnsupportedFeedtypeException e) {
|
} catch (UnsupportedFeedtypeException e) {
|
||||||
Log.d(TAG, "Unsupported feed type detected");
|
Log.d(TAG, "Unsupported feed type detected");
|
||||||
if ("html".equalsIgnoreCase(e.getRootElement())) {
|
if ("html".equalsIgnoreCase(e.getRootElement())) {
|
||||||
boolean dialogShown = showFeedDiscoveryDialog(new File(feed.getFile_url()), feed.getDownload_url());
|
boolean dialogShown = showFeedDiscoveryDialog(new File(feed.getFile_url()), feed.getDownload_url());
|
||||||
if (dialogShown) {
|
if (dialogShown) {
|
||||||
return Optional.empty();
|
return null; // Should not display an error message
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Supplied feed is an HTML web page that has no references to any feed");
|
Log.d(TAG, "Supplied feed is an HTML web page that has no references to any feed");
|
||||||
throw e;
|
throw e;
|
||||||
|
|
|
@ -56,7 +56,6 @@ import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||||
import de.danoeh.antennapod.core.util.FeedItemPermutors;
|
import de.danoeh.antennapod.core.util.FeedItemPermutors;
|
||||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||||
import de.danoeh.antennapod.core.util.Optional;
|
|
||||||
import de.danoeh.antennapod.ui.common.ThemeUtils;
|
import de.danoeh.antennapod.ui.common.ThemeUtils;
|
||||||
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
|
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
|
||||||
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
|
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
|
||||||
|
@ -549,15 +548,21 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
||||||
disposable = Observable.fromCallable(this::loadData)
|
disposable = Observable.fromCallable(this::loadData)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(result -> {
|
.subscribe(
|
||||||
feed = result.orElse(null);
|
result -> {
|
||||||
refreshHeaderView();
|
feed = result;
|
||||||
displayList();
|
refreshHeaderView();
|
||||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
displayList();
|
||||||
|
}, error -> {
|
||||||
|
feed = null;
|
||||||
|
refreshHeaderView();
|
||||||
|
displayList();
|
||||||
|
Log.e(TAG, Log.getStackTraceString(error));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@Nullable
|
||||||
private Optional<Feed> loadData() {
|
private Feed loadData() {
|
||||||
Feed feed = DBReader.getFeed(feedID);
|
Feed feed = DBReader.getFeed(feedID);
|
||||||
if (feed != null && feed.getItemFilter() != null) {
|
if (feed != null && feed.getItemFilter() != null) {
|
||||||
DBReader.loadAdditionalFeedItemListData(feed.getItems());
|
DBReader.loadAdditionalFeedItemListData(feed.getItems());
|
||||||
|
@ -569,7 +574,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
||||||
FeedItemPermutors.getPermutor(feed.getSortOrder()).reorder(feedItems);
|
FeedItemPermutors.getPermutor(feed.getSortOrder()).reorder(feedItems);
|
||||||
feed.setItems(feedItems);
|
feed.setItems(feedItems);
|
||||||
}
|
}
|
||||||
return Optional.ofNullable(feed);
|
return feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class FeedItemListAdapter extends EpisodeItemListAdapter {
|
private static class FeedItemListAdapter extends EpisodeItemListAdapter {
|
||||||
|
|
|
@ -1,213 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
package de.danoeh.antennapod.core.util;
|
|
||||||
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
// AntennaPod's stripped-down version of Java/Android platform's java.util.Optional
|
|
||||||
// so that it can be used on lower API level (API level 14)
|
|
||||||
|
|
||||||
// Android-changed: removed ValueBased paragraph.
|
|
||||||
/**
|
|
||||||
* A container object which may or may not contain a non-null value.
|
|
||||||
* If a value is present, {@code isPresent()} will return {@code true} and
|
|
||||||
* {@code get()} will return the value.
|
|
||||||
*
|
|
||||||
* <p>Additional methods that depend on the presence or absence of a contained
|
|
||||||
* value are provided, such as {@link #orElse(java.lang.Object) orElse()}
|
|
||||||
* (return a default value if value not present) and
|
|
||||||
* {@link #ifPresent(java.util.function.Consumer) ifPresent()} (execute a block
|
|
||||||
* of code if the value is present).
|
|
||||||
*
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public final class Optional<T> {
|
|
||||||
/**
|
|
||||||
* Common instance for {@code empty()}.
|
|
||||||
*/
|
|
||||||
private static final Optional<?> EMPTY = new Optional<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If non-null, the value; if null, indicates no value is present
|
|
||||||
*/
|
|
||||||
private final T value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an empty instance.
|
|
||||||
*
|
|
||||||
* @implNote Generally only one empty instance, {@link Optional#EMPTY},
|
|
||||||
* should exist per VM.
|
|
||||||
*/
|
|
||||||
private Optional() {
|
|
||||||
this.value = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an empty {@code Optional} instance. No value is present for this
|
|
||||||
* Optional.
|
|
||||||
*
|
|
||||||
* @apiNote Though it may be tempting to do so, avoid testing if an object
|
|
||||||
* is empty by comparing with {@code ==} against instances returned by
|
|
||||||
* {@code Option.empty()}. There is no guarantee that it is a singleton.
|
|
||||||
* Instead, use {@link #isPresent()}.
|
|
||||||
*
|
|
||||||
* @param <T> Type of the non-existent value
|
|
||||||
* @return an empty {@code Optional}
|
|
||||||
*/
|
|
||||||
public static <T> Optional<T> empty() {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Optional<T> t = (Optional<T>) EMPTY;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an instance with the value present.
|
|
||||||
*
|
|
||||||
* @param value the non-null value to be present
|
|
||||||
* @throws NullPointerException if value is null
|
|
||||||
*/
|
|
||||||
private Optional(T value) {
|
|
||||||
this.value = Objects.requireNonNull(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an {@code Optional} with the specified present non-null value.
|
|
||||||
*
|
|
||||||
* @param <T> the class of the value
|
|
||||||
* @param value the value to be present, which must be non-null
|
|
||||||
* @return an {@code Optional} with the value present
|
|
||||||
* @throws NullPointerException if value is null
|
|
||||||
*/
|
|
||||||
public static <T> Optional<T> of(T value) {
|
|
||||||
return new Optional<>(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an {@code Optional} describing the specified value, if non-null,
|
|
||||||
* otherwise returns an empty {@code Optional}.
|
|
||||||
*
|
|
||||||
* @param <T> the class of the value
|
|
||||||
* @param value the possibly-null value to describe
|
|
||||||
* @return an {@code Optional} with a present value if the specified value
|
|
||||||
* is non-null, otherwise an empty {@code Optional}
|
|
||||||
*/
|
|
||||||
public static <T> Optional<T> ofNullable(T value) {
|
|
||||||
return value == null ? empty() : of(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a value is present in this {@code Optional}, returns the value,
|
|
||||||
* otherwise throws {@code NoSuchElementException}.
|
|
||||||
*
|
|
||||||
* @return the non-null value held by this {@code Optional}
|
|
||||||
* @throws NoSuchElementException if there is no value present
|
|
||||||
*
|
|
||||||
* @see Optional#isPresent()
|
|
||||||
*/
|
|
||||||
public T get() {
|
|
||||||
if (value == null) {
|
|
||||||
throw new NoSuchElementException("No value present");
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return {@code true} if there is a value present, otherwise {@code false}.
|
|
||||||
*
|
|
||||||
* @return {@code true} if there is a value present, otherwise {@code false}
|
|
||||||
*/
|
|
||||||
public boolean isPresent() {
|
|
||||||
return value != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the value if present, otherwise return {@code other}.
|
|
||||||
*
|
|
||||||
* @param other the value to be returned if there is no value present, may
|
|
||||||
* be null
|
|
||||||
* @return the value, if present, otherwise {@code other}
|
|
||||||
*/
|
|
||||||
public T orElse(T other) {
|
|
||||||
return value != null ? value : other;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether some other object is "equal to" this Optional. The
|
|
||||||
* other object is considered equal if:
|
|
||||||
* <ul>
|
|
||||||
* <li>it is also an {@code Optional} and;
|
|
||||||
* <li>both instances have no value present or;
|
|
||||||
* <li>the present values are "equal to" each other via {@code equals()}.
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param obj an object to be tested for equality
|
|
||||||
* @return {code true} if the other object is "equal to" this object
|
|
||||||
* otherwise {@code false}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(obj instanceof Optional)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<?> other = (Optional<?>) obj;
|
|
||||||
return (value == other.value) || (value != null && value.equals(other.value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the hash code value of the present value, if any, or 0 (zero) if
|
|
||||||
* no value is present.
|
|
||||||
*
|
|
||||||
* @return hash code value of the present value or 0 if no value is present
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return value != null ? value.hashCode() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a non-empty string representation of this Optional suitable for
|
|
||||||
* debugging. The exact presentation format is unspecified and may vary
|
|
||||||
* between implementations and versions.
|
|
||||||
*
|
|
||||||
* @implSpec If a value is present the result must include its string
|
|
||||||
* representation in the result. Empty and present Optionals must be
|
|
||||||
* unambiguously differentiable.
|
|
||||||
*
|
|
||||||
* @return the string representation of this instance
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return value != null
|
|
||||||
? String.format("Optional[%s]", value)
|
|
||||||
: "Optional.empty";
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue