mirror of
https://github.com/AntennaPod/AntennaPod.git
synced 2025-12-01 12:31:45 +00:00
Open podcast or episode from download log details (#7867)
This commit is contained in:
@ -0,0 +1,126 @@
|
|||||||
|
package de.test.antennapod.ui;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import androidx.test.espresso.intent.rule.IntentsTestRule;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
import de.danoeh.antennapod.R;
|
||||||
|
import de.danoeh.antennapod.activity.MainActivity;
|
||||||
|
import de.danoeh.antennapod.model.download.DownloadError;
|
||||||
|
import de.danoeh.antennapod.model.download.DownloadResult;
|
||||||
|
import de.danoeh.antennapod.model.feed.Feed;
|
||||||
|
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||||
|
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||||
|
import de.danoeh.antennapod.storage.database.DBWriter;
|
||||||
|
import de.danoeh.antennapod.storage.database.FeedDatabaseWriter;
|
||||||
|
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
|
||||||
|
import de.danoeh.antennapod.ui.screen.download.CompletedDownloadsFragment;
|
||||||
|
import de.test.antennapod.EspressoTestUtils;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import static androidx.test.espresso.Espresso.onView;
|
||||||
|
import static androidx.test.espresso.action.ViewActions.click;
|
||||||
|
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
import static de.test.antennapod.EspressoTestUtils.waitForView;
|
||||||
|
import static de.test.antennapod.EspressoTestUtils.waitForViewGlobally;
|
||||||
|
import static org.hamcrest.CoreMatchers.not;
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class DownloadLogTest {
|
||||||
|
@Rule
|
||||||
|
public IntentsTestRule<MainActivity> activityRule = new IntentsTestRule<>(MainActivity.class, false, false);
|
||||||
|
private Context context;
|
||||||
|
private Intent completedDownloadsIntent;
|
||||||
|
private Feed feed;
|
||||||
|
private FeedMedia media;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
EspressoTestUtils.clearPreferences();
|
||||||
|
EspressoTestUtils.clearDatabase();
|
||||||
|
context = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
|
completedDownloadsIntent = new Intent(context, MainActivity.class);
|
||||||
|
completedDownloadsIntent.putExtra(MainActivityStarter.EXTRA_FRAGMENT_TAG, CompletedDownloadsFragment.TAG);
|
||||||
|
|
||||||
|
feed = new Feed(0, "last modified", "@@Feed title@@", "link", "description", "payment link",
|
||||||
|
"@author@", "language", "type", "feedIdentifier", "http://localhost/cover.png",
|
||||||
|
"/sdcard/abc", "http://localhost/feed.xml", 0);
|
||||||
|
FeedItem item = new FeedItem(0, "title", "identifier", "link", new Date(), FeedItem.UNPLAYED, feed);
|
||||||
|
media = new FeedMedia(item, "http://localhost/media.mp3", 10000, "mime type");
|
||||||
|
item.setMedia(media);
|
||||||
|
feed.setItems(Collections.singletonList(item));
|
||||||
|
feed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingSubscribedFeed() {
|
||||||
|
DownloadResult result = new DownloadResult("@@Title@@", feed.getId(),
|
||||||
|
Feed.FEEDFILETYPE_FEED, false, DownloadError.ERROR_IO_ERROR, "@@reason@@");
|
||||||
|
openDialog(result);
|
||||||
|
// Open feed
|
||||||
|
onView(withText(R.string.download_log_open_feed)).perform(click());
|
||||||
|
waitForViewGlobally(withText(feed.getAuthor()), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingNonSubscribedFeed() throws InterruptedException, ExecutionException {
|
||||||
|
DBWriter.setFeedState(context, feed, Feed.STATE_NOT_SUBSCRIBED).get();
|
||||||
|
DownloadResult result = new DownloadResult("@@Title@@", feed.getId(),
|
||||||
|
Feed.FEEDFILETYPE_FEED, false, DownloadError.ERROR_IO_ERROR, "@@reason@@");
|
||||||
|
openDialog(result);
|
||||||
|
// Opens online feed view
|
||||||
|
onView(withText(R.string.download_log_open_feed)).perform(click());
|
||||||
|
waitForViewGlobally(withText(feed.getAuthor()), 2000);
|
||||||
|
onView(isRoot()).perform(waitForView(allOf(withText(R.string.subscribe_label), isDisplayed()), 2000));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonExistingFeed() {
|
||||||
|
DownloadResult result = new DownloadResult("@@Title@@", feed.getId() + 1,
|
||||||
|
Feed.FEEDFILETYPE_FEED, false, DownloadError.ERROR_IO_ERROR, "@@reason@@");
|
||||||
|
openDialog(result);
|
||||||
|
// Does not have button
|
||||||
|
onView(withText(R.string.download_log_open_feed)).check(matches(not(isDisplayed())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingMedia() {
|
||||||
|
DownloadResult result = new DownloadResult("@@Title@@", media.getId(),
|
||||||
|
FeedMedia.FEEDFILETYPE_FEEDMEDIA, false, DownloadError.ERROR_IO_ERROR, "@@reason@@");
|
||||||
|
openDialog(result);
|
||||||
|
// Opens feed
|
||||||
|
onView(withText(R.string.download_log_open_feed)).perform(click());
|
||||||
|
waitForViewGlobally(withText(feed.getAuthor()), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonExistingMedia() {
|
||||||
|
DownloadResult result = new DownloadResult("@@Title@@", media.getId() + 1,
|
||||||
|
FeedMedia.FEEDFILETYPE_FEEDMEDIA, false, DownloadError.ERROR_IO_ERROR, "@@reason@@");
|
||||||
|
openDialog(result);
|
||||||
|
// Does not have button
|
||||||
|
onView(withText(R.string.download_log_open_feed)).check(matches(not(isDisplayed())));
|
||||||
|
}
|
||||||
|
|
||||||
|
void openDialog(DownloadResult result) {
|
||||||
|
DBWriter.addDownloadStatus(result);
|
||||||
|
activityRule.launchActivity(completedDownloadsIntent);
|
||||||
|
onView(withContentDescription(R.string.downloads_log_label)).perform(click());
|
||||||
|
onView(isRoot()).perform(waitForView(allOf(withText(result.getTitle()), isDisplayed()), 1000));
|
||||||
|
onView(withText(result.getTitle())).perform(click());
|
||||||
|
onView(isRoot()).perform(waitForView(allOf(withText(result.getReasonDetailed()), isDisplayed()), 1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -707,7 +707,7 @@ public class MainActivity extends CastEnabledActivity {
|
|||||||
drawerLayout.open();
|
drawerLayout.open();
|
||||||
}
|
}
|
||||||
if (intent.getBooleanExtra(MainActivityStarter.EXTRA_OPEN_DOWNLOAD_LOGS, false)) {
|
if (intent.getBooleanExtra(MainActivityStarter.EXTRA_OPEN_DOWNLOAD_LOGS, false)) {
|
||||||
new DownloadLogFragment().show(getSupportFragmentManager(), null);
|
new DownloadLogFragment().show(getSupportFragmentManager(), DownloadLogFragment.TAG);
|
||||||
}
|
}
|
||||||
if (intent.getBooleanExtra(EXTRA_REFRESH_ON_START, false)) {
|
if (intent.getBooleanExtra(EXTRA_REFRESH_ON_START, false)) {
|
||||||
FeedUpdateManager.getInstance().runOnceOrAsk(this);
|
FeedUpdateManager.getInstance().runOnceOrAsk(this);
|
||||||
|
|||||||
@ -131,7 +131,7 @@ public class CompletedDownloadsFragment extends Fragment
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (getArguments() != null && getArguments().getBoolean(ARG_SHOW_LOGS, false)) {
|
if (getArguments() != null && getArguments().getBoolean(ARG_SHOW_LOGS, false)) {
|
||||||
new DownloadLogFragment().show(getChildFragmentManager(), null);
|
new DownloadLogFragment().show(getChildFragmentManager(), DownloadLogFragment.TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
addEmptyView();
|
addEmptyView();
|
||||||
@ -176,7 +176,7 @@ public class CompletedDownloadsFragment extends Fragment
|
|||||||
FeedUpdateManager.getInstance().runOnceOrAsk(requireContext());
|
FeedUpdateManager.getInstance().runOnceOrAsk(requireContext());
|
||||||
return true;
|
return true;
|
||||||
} else if (item.getItemId() == R.id.action_download_logs) {
|
} else if (item.getItemId() == R.id.action_download_logs) {
|
||||||
new DownloadLogFragment().show(getChildFragmentManager(), null);
|
new DownloadLogFragment().show(getChildFragmentManager(), DownloadLogFragment.TAG);
|
||||||
return true;
|
return true;
|
||||||
} else if (item.getItemId() == R.id.action_search) {
|
} else if (item.getItemId() == R.id.action_search) {
|
||||||
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance());
|
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance());
|
||||||
|
|||||||
@ -1,71 +1,169 @@
|
|||||||
package de.danoeh.antennapod.ui.screen.download;
|
package de.danoeh.antennapod.ui.screen.download;
|
||||||
|
|
||||||
import android.content.ClipData;
|
import android.app.Dialog;
|
||||||
import android.content.ClipboardManager;
|
import android.content.Intent;
|
||||||
import android.content.Context;
|
import android.os.Bundle;
|
||||||
import android.os.Build;
|
import android.util.Log;
|
||||||
import android.text.Spannable;
|
import android.view.View;
|
||||||
import android.text.SpannableString;
|
|
||||||
import android.text.style.ForegroundColorSpan;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
|
import de.danoeh.antennapod.databinding.DownloadLogDetailsDialogBinding;
|
||||||
import de.danoeh.antennapod.model.download.DownloadResult;
|
import de.danoeh.antennapod.model.download.DownloadResult;
|
||||||
import de.danoeh.antennapod.storage.database.DBReader;
|
|
||||||
import de.danoeh.antennapod.event.MessageEvent;
|
|
||||||
import de.danoeh.antennapod.model.feed.Feed;
|
import de.danoeh.antennapod.model.feed.Feed;
|
||||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import de.danoeh.antennapod.storage.database.DBReader;
|
||||||
|
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
|
||||||
|
import de.danoeh.antennapod.ui.appstartintent.OnlineFeedviewActivityStarter;
|
||||||
|
import de.danoeh.antennapod.ui.common.ClipboardUtils;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
|
|
||||||
public class DownloadLogDetailsDialog extends MaterialAlertDialogBuilder {
|
/**
|
||||||
|
* Shows a dialog with Feed title (and FeedItem title if possible).
|
||||||
|
* Can show a button to jump to the feed details view.
|
||||||
|
*/
|
||||||
|
public class DownloadLogDetailsDialog extends DialogFragment {
|
||||||
|
public static final String TAG = "DownloadLogDetails";
|
||||||
|
private static final String EXTRA_IS_JUMP_TO_FEED = "isJumpToFeed";
|
||||||
|
private static final String EXTRA_DOWNLOAD_RESULT = "downloadResult";
|
||||||
|
private DownloadLogDetailsDialogBinding viewBinding;
|
||||||
|
private Disposable disposable;
|
||||||
|
private boolean isJumpToFeed;
|
||||||
|
private DownloadResult downloadResult;
|
||||||
|
private Feed feed = null;
|
||||||
|
private String podcastName = null;
|
||||||
|
private String episodeName = null;
|
||||||
|
private String url = "unknown";
|
||||||
|
private String clipboardContent = "";
|
||||||
|
|
||||||
public DownloadLogDetailsDialog(@NonNull Context context, DownloadResult status) {
|
public static DownloadLogDetailsDialog newInstance(DownloadResult downloadResult, boolean isJumpToFeed) {
|
||||||
super(context);
|
DownloadLogDetailsDialog dialog = new DownloadLogDetailsDialog();
|
||||||
|
Bundle args = new Bundle();
|
||||||
String url = "unknown";
|
args.putSerializable(EXTRA_DOWNLOAD_RESULT, downloadResult);
|
||||||
if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
|
args.putBoolean(EXTRA_IS_JUMP_TO_FEED, isJumpToFeed);
|
||||||
FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId());
|
dialog.setArguments(args);
|
||||||
if (media != null) {
|
return dialog;
|
||||||
url = media.getDownloadUrl();
|
|
||||||
}
|
|
||||||
} else if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
|
|
||||||
Feed feed = DBReader.getFeed(status.getFeedfileId(), false, 0, 0);
|
|
||||||
if (feed != null) {
|
|
||||||
url = feed.getDownloadUrl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String message = context.getString(R.string.download_successful);
|
|
||||||
if (!status.isSuccessful()) {
|
|
||||||
message = status.getReasonDetailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
String humanReadableReason = context.getString(DownloadErrorLabel.from(status.getReason()));
|
|
||||||
SpannableString errorMessage = new SpannableString(context.getString(R.string.download_log_details_message,
|
|
||||||
humanReadableReason, message, url));
|
|
||||||
errorMessage.setSpan(new ForegroundColorSpan(0x88888888),
|
|
||||||
humanReadableReason.length(), errorMessage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
|
|
||||||
setTitle(R.string.download_error_details);
|
|
||||||
setMessage(errorMessage);
|
|
||||||
setPositiveButton(android.R.string.ok, null);
|
|
||||||
setNeutralButton(R.string.copy_to_clipboard, (dialog, which) -> {
|
|
||||||
ClipboardManager clipboard = (ClipboardManager) getContext()
|
|
||||||
.getSystemService(Context.CLIPBOARD_SERVICE);
|
|
||||||
ClipData clip = ClipData.newPlainText(context.getString(R.string.download_error_details), errorMessage);
|
|
||||||
clipboard.setPrimaryClip(clip);
|
|
||||||
if (Build.VERSION.SDK_INT < 32) {
|
|
||||||
EventBus.getDefault().post(new MessageEvent(context.getString(R.string.copied_to_clipboard)));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AlertDialog show() {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
AlertDialog dialog = super.show();
|
super.onCreate(savedInstanceState);
|
||||||
((TextView) dialog.findViewById(android.R.id.message)).setTextIsSelectable(true);
|
downloadResult = (DownloadResult) getArguments().getSerializable(EXTRA_DOWNLOAD_RESULT);
|
||||||
return dialog;
|
isJumpToFeed = getArguments().getBoolean(EXTRA_IS_JUMP_TO_FEED, true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
|
MaterialAlertDialogBuilder dialog = new MaterialAlertDialogBuilder(getContext());
|
||||||
|
dialog.setTitle(R.string.download_error_details);
|
||||||
|
dialog.setPositiveButton(android.R.string.ok, null);
|
||||||
|
dialog.setNeutralButton(R.string.copy_to_clipboard, (copyDialog, which) ->
|
||||||
|
ClipboardUtils.copyText(viewBinding.getRoot(), R.string.download_error_details, clipboardContent));
|
||||||
|
|
||||||
|
viewBinding = DownloadLogDetailsDialogBinding.inflate(getLayoutInflater());
|
||||||
|
dialog.setView(viewBinding.getRoot());
|
||||||
|
|
||||||
|
viewBinding.goToPodcastButton.setVisibility(View.GONE);
|
||||||
|
viewBinding.goToPodcastButton.setOnClickListener(v -> {
|
||||||
|
goToFeed();
|
||||||
|
dismiss();
|
||||||
|
Fragment downloadLog = getParentFragmentManager().findFragmentByTag(DownloadLogFragment.TAG);
|
||||||
|
if (downloadLog instanceof DownloadLogFragment) {
|
||||||
|
((DownloadLogFragment) downloadLog).dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
viewBinding.fileUrlLabel.setOnClickListener(v ->
|
||||||
|
ClipboardUtils.copyText(viewBinding.fileUrlLabel, R.string.download_log_details_file_url_title));
|
||||||
|
viewBinding.technicalReasonLabel.setOnClickListener(v ->
|
||||||
|
ClipboardUtils.copyText(viewBinding.technicalReasonLabel,
|
||||||
|
R.string.download_log_details_technical_reason_title));
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
return dialog.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (disposable != null) {
|
||||||
|
disposable.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadData() {
|
||||||
|
if (disposable != null) {
|
||||||
|
disposable.dispose();
|
||||||
|
}
|
||||||
|
disposable = Single.create(emitter -> {
|
||||||
|
if (downloadResult.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
|
||||||
|
FeedMedia media = DBReader.getFeedMedia(downloadResult.getFeedfileId());
|
||||||
|
if (media != null) {
|
||||||
|
if (media.getItem() != null && media.getItem().getFeed() != null) {
|
||||||
|
feed = media.getItem().getFeed();
|
||||||
|
podcastName = feed.getTitle();
|
||||||
|
}
|
||||||
|
episodeName = media.getEpisodeTitle();
|
||||||
|
url = media.getDownloadUrl();
|
||||||
|
} else {
|
||||||
|
episodeName = downloadResult.getTitle();
|
||||||
|
}
|
||||||
|
} else if (downloadResult.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
|
||||||
|
feed = DBReader.getFeed(downloadResult.getFeedfileId(), false, 0, 0);
|
||||||
|
if (feed != null) {
|
||||||
|
podcastName = feed.getTitle();
|
||||||
|
url = feed.getDownloadUrl();
|
||||||
|
} else {
|
||||||
|
podcastName = downloadResult.getTitle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emitter.onSuccess(true);
|
||||||
|
})
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(obj -> updateUi(),
|
||||||
|
error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateUi() {
|
||||||
|
String message = getString(R.string.download_successful);
|
||||||
|
if (!downloadResult.isSuccessful()) {
|
||||||
|
message = downloadResult.getReasonDetailed();
|
||||||
|
}
|
||||||
|
viewBinding.goToPodcastButton.setVisibility((isJumpToFeed && feed != null) ? View.VISIBLE : View.GONE);
|
||||||
|
viewBinding.podcastNameLabel.setText(podcastName);
|
||||||
|
viewBinding.podcastContainer.setVisibility(podcastName == null ? View.GONE : View.VISIBLE);
|
||||||
|
viewBinding.episodeNameLabel.setText(episodeName);
|
||||||
|
viewBinding.episodeContainer.setVisibility(episodeName == null ? View.GONE : View.VISIBLE);
|
||||||
|
|
||||||
|
final String humanReadableReason = getString(DownloadErrorLabel.from(downloadResult.getReason()));
|
||||||
|
viewBinding.humanReadableReasonLabel.setText(humanReadableReason);
|
||||||
|
viewBinding.technicalReasonLabel.setText(message);
|
||||||
|
viewBinding.fileUrlLabel.setText(url);
|
||||||
|
|
||||||
|
final String humanReadableReasonTitle = getString(R.string.download_log_details_human_readable_reason_title);
|
||||||
|
final String technicalReasonTitle = getString(R.string.download_log_details_technical_reason_title);
|
||||||
|
final String urlTitle = getString(R.string.download_log_details_file_url_title);
|
||||||
|
clipboardContent = String.format("%s: \n%s \n\n%s: \n%s \n\n%s: \n%s",
|
||||||
|
humanReadableReasonTitle, humanReadableReason, technicalReasonTitle, message, urlTitle, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void goToFeed() {
|
||||||
|
if (feed == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Intent intent;
|
||||||
|
if (feed.getState() == Feed.STATE_SUBSCRIBED) {
|
||||||
|
intent = new MainActivityStarter(getContext()).withOpenFeed(feed.getId()).getIntent();
|
||||||
|
} else {
|
||||||
|
intent = new OnlineFeedviewActivityStarter(getContext(), feed.getDownloadUrl()).getIntent();
|
||||||
|
}
|
||||||
|
getContext().startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,14 +12,14 @@ import androidx.annotation.Nullable;
|
|||||||
import com.google.android.material.appbar.MaterialToolbar;
|
import com.google.android.material.appbar.MaterialToolbar;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
|
import de.danoeh.antennapod.databinding.DownloadLogFragmentBinding;
|
||||||
import de.danoeh.antennapod.event.DownloadLogEvent;
|
import de.danoeh.antennapod.event.DownloadLogEvent;
|
||||||
|
import de.danoeh.antennapod.model.download.DownloadResult;
|
||||||
import de.danoeh.antennapod.storage.database.DBReader;
|
import de.danoeh.antennapod.storage.database.DBReader;
|
||||||
import de.danoeh.antennapod.storage.database.DBWriter;
|
import de.danoeh.antennapod.storage.database.DBWriter;
|
||||||
import de.danoeh.antennapod.databinding.DownloadLogFragmentBinding;
|
|
||||||
import de.danoeh.antennapod.model.download.DownloadResult;
|
|
||||||
import de.danoeh.antennapod.ui.view.EmptyViewHandler;
|
import de.danoeh.antennapod.ui.view.EmptyViewHandler;
|
||||||
import io.reactivex.rxjava3.core.Observable;
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
@ -33,7 +33,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class DownloadLogFragment extends BottomSheetDialogFragment
|
public class DownloadLogFragment extends BottomSheetDialogFragment
|
||||||
implements AdapterView.OnItemClickListener, MaterialToolbar.OnMenuItemClickListener {
|
implements AdapterView.OnItemClickListener, MaterialToolbar.OnMenuItemClickListener {
|
||||||
private static final String TAG = "DownloadLogFragment";
|
public static final String TAG = "DownloadLogFragment";
|
||||||
|
|
||||||
private List<DownloadResult> downloadLog = new ArrayList<>();
|
private List<DownloadResult> downloadLog = new ArrayList<>();
|
||||||
private DownloadLogAdapter adapter;
|
private DownloadLogAdapter adapter;
|
||||||
@ -86,7 +86,8 @@ public class DownloadLogFragment extends BottomSheetDialogFragment
|
|||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
final DownloadResult item = adapter.getItem(position);
|
final DownloadResult item = adapter.getItem(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
new DownloadLogDetailsDialog(getContext(), item).show();
|
DownloadLogDetailsDialog.newInstance(item, true)
|
||||||
|
.show(getParentFragmentManager(), DownloadLogDetailsDialog.TAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -624,9 +624,10 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
downloadStatus -> new DownloadLogDetailsDialog(getContext(), downloadStatus).show(),
|
downloadStatus -> DownloadLogDetailsDialog.newInstance(downloadStatus, false)
|
||||||
|
.show(getChildFragmentManager(), DownloadLogDetailsDialog.TAG),
|
||||||
error -> error.printStackTrace(),
|
error -> error.printStackTrace(),
|
||||||
() -> new DownloadLogFragment().show(getChildFragmentManager(), null));
|
() -> new DownloadLogFragment().show(getChildFragmentManager(), DownloadLogFragment.TAG));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showFeedInfo() {
|
private void showFeedInfo() {
|
||||||
|
|||||||
154
app/src/main/res/layout/download_log_details_dialog.xml
Normal file
154
app/src/main/res/layout/download_log_details_dialog.xml
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="?dialogPreferredPadding">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Podcast header, podcast title, button to jump to podcast -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/podcastContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/feed"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
style="@style/TextAppearance.Material3.TitleMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/podcastNameLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
tools:text="Podcast name" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/goToPodcastButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:text="@string/download_log_open_feed"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Episode header, episode title -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/episodeContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginTop="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/episode"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
style="@style/TextAppearance.Material3.TitleMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/episodeNameLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="middle"
|
||||||
|
tools:text="Episode Name" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Human readable reason for the message/error -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/humanReadableReasonContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginTop="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/download_log_details_human_readable_reason_title"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
style="@style/TextAppearance.Material3.TitleMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/humanReadableReasonLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="@string/download_error_not_found" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Technical details/reason -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/technicalReasonContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginTop="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/download_log_details_technical_reason_title"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
style="@style/TextAppearance.Material3.TitleMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/technicalReasonLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
tools:text="Http error 404" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- File URL -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/fileUrlContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginTop="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/download_log_details_file_url_title"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
style="@style/TextAppearance.Material3.TitleMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/fileUrlLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
tools:text="http://example.com/feed.xml" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
@ -2,12 +2,15 @@ package de.danoeh.antennapod.model.download;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains status attributes for one download
|
* Contains status attributes for one download
|
||||||
*/
|
*/
|
||||||
public class DownloadResult {
|
public class DownloadResult implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloaders should use this constant for the size attribute if necessary
|
* Downloaders should use this constant for the size attribute if necessary
|
||||||
* so that the listadapters etc. can react properly.
|
* so that the listadapters etc. can react properly.
|
||||||
|
|||||||
@ -304,6 +304,10 @@
|
|||||||
<string name="download_running">Download running</string>
|
<string name="download_running">Download running</string>
|
||||||
<string name="download_error_details">Details</string>
|
<string name="download_error_details">Details</string>
|
||||||
<string name="download_log_details_message">%1$s \n\nTechnical reason: \n%2$s \n\nFile URL:\n%3$s</string>
|
<string name="download_log_details_message">%1$s \n\nTechnical reason: \n%2$s \n\nFile URL:\n%3$s</string>
|
||||||
|
<string name="download_log_details_human_readable_reason_title">Status</string>
|
||||||
|
<string name="download_log_details_technical_reason_title">Technical details</string>
|
||||||
|
<string name="download_log_details_file_url_title">File URL</string>
|
||||||
|
<string name="download_log_open_feed">Open</string>
|
||||||
<string name="download_error_retrying">Download of \"%1$s\" failed. Will be retried later.</string>
|
<string name="download_error_retrying">Download of \"%1$s\" failed. Will be retried later.</string>
|
||||||
<string name="download_error_not_retrying">Download of \"%1$s\" failed.</string>
|
<string name="download_error_not_retrying">Download of \"%1$s\" failed.</string>
|
||||||
<string name="download_error_tap_for_details">Tap to view details.</string>
|
<string name="download_error_tap_for_details">Tap to view details.</string>
|
||||||
@ -387,7 +391,9 @@
|
|||||||
<string name="keep_sorted">Keep sorted</string>
|
<string name="keep_sorted">Keep sorted</string>
|
||||||
<string name="date">Date</string>
|
<string name="date">Date</string>
|
||||||
<string name="duration">Duration</string>
|
<string name="duration">Duration</string>
|
||||||
|
<string name="episode">Episode</string>
|
||||||
<string name="episode_title">Episode title</string>
|
<string name="episode_title">Episode title</string>
|
||||||
|
<string name="feed">Podcast</string>
|
||||||
<string name="feed_title">Podcast title</string>
|
<string name="feed_title">Podcast title</string>
|
||||||
<string name="random">Random</string>
|
<string name="random">Random</string>
|
||||||
<string name="smart_shuffle">Smart shuffle</string>
|
<string name="smart_shuffle">Smart shuffle</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user