Merge pull request #4260 from gerardolgvr/replace-share-menu-by-dialog

fixes #1215 replacing share menu by dialog
This commit is contained in:
H. Lehmann 2020-07-11 17:50:00 +02:00 committed by GitHub
commit d110b1818b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 304 additions and 125 deletions

View File

@ -0,0 +1,92 @@
package de.test.antennapod.dialogs;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import androidx.test.espresso.intent.rule.IntentsTestRule;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.fragment.EpisodesFragment;
import de.test.antennapod.EspressoTestUtils;
import de.test.antennapod.ui.UITestUtils;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
import static androidx.test.espresso.matcher.ViewMatchers.hasMinimumChildCount;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.test.antennapod.EspressoTestUtils.onDrawerItem;
import static de.test.antennapod.EspressoTestUtils.openNavDrawer;
import static de.test.antennapod.EspressoTestUtils.waitForView;
import static de.test.antennapod.NthMatcher.first;
import static org.hamcrest.CoreMatchers.allOf;
/**
* User interface tests for share dialog.
*/
@RunWith(AndroidJUnit4.class)
public class ShareDialogTest {
@Rule
public IntentsTestRule<MainActivity> activityRule = new IntentsTestRule<>(MainActivity.class, false, false);
private UITestUtils uiTestUtils;
protected Context context;
@Before
public void setUp() throws Exception {
context = InstrumentationRegistry.getInstrumentation().getTargetContext();
EspressoTestUtils.clearPreferences();
EspressoTestUtils.clearDatabase();
EspressoTestUtils.setLastNavFragment(EpisodesFragment.TAG);
uiTestUtils = new UITestUtils(context);
uiTestUtils.setup();
uiTestUtils.addLocalFeedData(true);
activityRule.launchActivity(new Intent());
openNavDrawer();
onDrawerItem(withText(R.string.episodes_label)).perform(click());
onView(isRoot()).perform(waitForView(withText(R.string.all_episodes_short_label), 1000));
onView(withText(R.string.all_episodes_short_label)).perform(click());
Matcher<View> allEpisodesMatcher;
final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(0, 10);
allEpisodesMatcher = Matchers.allOf(withId(android.R.id.list), isDisplayed(), hasMinimumChildCount(2));
onView(isRoot()).perform(waitForView(allEpisodesMatcher, 1000));
onView(allEpisodesMatcher).perform(actionOnItemAtPosition(0, click()));
onView(first(EspressoTestUtils.actionBarOverflow())).perform(click());
}
@Test
public void testShareDialogDisplayed() throws InterruptedException {
onView(withText(R.string.share_label_with_ellipses)).perform(click());
onView(allOf(isDisplayed(), withText(R.string.share_label)));
}
@Test
public void testShareDialogCancelButton() {
onView(withText(R.string.share_label_with_ellipses)).perform(scrollTo()).perform(click());
onView(withText(R.string.cancel_label)).check(matches(isDisplayed())).perform(scrollTo()).perform(click());
}
}

View File

@ -18,16 +18,23 @@ import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.text.NumberFormat;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.arch.core.util.Function;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;
import androidx.core.util.Supplier;
import com.bumptech.glide.Glide;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
@ -39,7 +46,6 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.Flavors;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
@ -51,18 +57,13 @@ import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
import de.danoeh.antennapod.dialog.PlaybackControlsDialog;
import de.danoeh.antennapod.dialog.ShareDialog;
import de.danoeh.antennapod.dialog.SkipPreferenceDialog;
import de.danoeh.antennapod.dialog.SleepTimerDialog;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.text.NumberFormat;
/**
@ -313,13 +314,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
boolean isItemAndHasLink = isFeedMedia &&
ShareUtils.hasLinkToShare(((FeedMedia) media).getItem());
menu.findItem(R.id.share_link_item).setVisible(isItemAndHasLink);
menu.findItem(R.id.share_link_with_position_item).setVisible(isItemAndHasLink);
boolean isItemHasDownloadLink = isFeedMedia && ((FeedMedia) media).getDownload_url() != null;
menu.findItem(R.id.share_download_url_item).setVisible(isItemHasDownloadLink);
menu.findItem(R.id.share_download_url_with_position_item).setVisible(isItemHasDownloadLink);
menu.findItem(R.id.share_file).setVisible(isFeedMedia && ((FeedMedia) media).fileExists());
menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink);
@ -393,29 +389,10 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
case R.id.visit_website_item:
IntentUtils.openInBrowser(MediaplayerActivity.this, getWebsiteLinkWithFallback(media));
break;
case R.id.share_link_item:
case R.id.share_item:
if (feedItem != null) {
ShareUtils.shareFeedItemLink(this, feedItem);
}
break;
case R.id.share_download_url_item:
if (feedItem != null) {
ShareUtils.shareFeedItemDownloadLink(this, feedItem);
}
break;
case R.id.share_link_with_position_item:
if (feedItem != null) {
ShareUtils.shareFeedItemLink(this, feedItem, true);
}
break;
case R.id.share_download_url_with_position_item:
if (feedItem != null) {
ShareUtils.shareFeedItemDownloadLink(this, feedItem, true);
}
break;
case R.id.share_file:
if (media instanceof FeedMedia) {
ShareUtils.shareFeedItemFile(this, ((FeedMedia) media));
ShareDialog shareDialog = ShareDialog.newInstance(feedItem);
shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog");
}
break;
default:

View File

@ -0,0 +1,120 @@
package de.danoeh.antennapod.dialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.util.ShareUtils;
public class ShareDialog extends DialogFragment {
private static final String ARGUMENT_FEED_ITEM = "feedItem";
private static final String TAG = "ShareDialog";
private Context ctx;
private FeedItem item;
private static final String PREF_SHARE_DIALOG_OPTION = "prefShareDialogOption";
private static final String PREF_SHARE_EPISODE_START_AT = "prefShareEpisodeStartAt";
private RadioGroup radioGroup;
private RadioButton radioEpisodeWebsite;
private RadioButton radioMediaFile;
private CheckBox checkBoxStartAt;
private SharedPreferences prefs;
public ShareDialog() {
// Empty constructor required for DialogFragment
}
public static ShareDialog newInstance(FeedItem item) {
Bundle arguments = new Bundle();
arguments.putSerializable(ARGUMENT_FEED_ITEM, item);
ShareDialog dialog = new ShareDialog();
dialog.setArguments(arguments);
return dialog;
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
if (getArguments() != null) {
ctx = getActivity();
item = (FeedItem) getArguments().getSerializable(ARGUMENT_FEED_ITEM);
prefs = getActivity().getSharedPreferences("ShareDialog", Context.MODE_PRIVATE);
}
View content = View.inflate(ctx, R.layout.share_episode_dialog, null);
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle(R.string.share_label);
builder.setView(content);
radioGroup = content.findViewById(R.id.share_dialog_radio_group);
radioEpisodeWebsite = content.findViewById(R.id.share_episode_website_radio);
radioMediaFile = content.findViewById(R.id.share_media_file_radio);
checkBoxStartAt = content.findViewById(R.id.share_start_at_timer_dialog);
setupOptions();
builder.setPositiveButton(R.string.share_label, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
boolean includePlaybackPosition = checkBoxStartAt.isChecked();
if (radioEpisodeWebsite.isChecked()) {
ShareUtils.shareFeedItemLink(ctx, item, includePlaybackPosition);
prefs.edit().putString(PREF_SHARE_DIALOG_OPTION, "website").apply();
} else {
ShareUtils.shareFeedItemDownloadLink(ctx, item, includePlaybackPosition);
prefs.edit().putString(PREF_SHARE_DIALOG_OPTION, "media").apply();
}
prefs.edit().putBoolean(PREF_SHARE_EPISODE_START_AT, includePlaybackPosition).apply();
}
}).setNegativeButton(R.string.cancel_label, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
return builder.create();
}
private void setupOptions() {
final boolean hasMedia = item.getMedia() != null;
if (!ShareUtils.hasLinkToShare(item)) {
radioEpisodeWebsite.setVisibility(View.GONE);
radioMediaFile.setChecked(true);
}
if (!hasMedia || item.getMedia().getDownload_url() == null) {
radioMediaFile.setVisibility(View.GONE);
radioEpisodeWebsite.setChecked(true);
}
if (radioEpisodeWebsite.getVisibility() == View.VISIBLE && radioMediaFile.getVisibility() == View.VISIBLE) {
String option = prefs.getString(PREF_SHARE_DIALOG_OPTION, "website");
if (option.equals("website")) {
radioEpisodeWebsite.setChecked(true);
radioMediaFile.setChecked(false);
} else {
radioEpisodeWebsite.setChecked(false);
radioMediaFile.setChecked(true);
}
}
boolean switchIsChecked = prefs.getBoolean(PREF_SHARE_EPISODE_START_AT, false);
checkBoxStartAt.setChecked(switchIsChecked);
}
}

View File

@ -2,13 +2,14 @@ package de.danoeh.antennapod.menuhandler;
import android.content.Context;
import android.os.Handler;
import androidx.annotation.NonNull;
import com.google.android.material.snackbar.Snackbar;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import com.google.android.material.snackbar.Snackbar;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem;
@ -23,6 +24,7 @@ import de.danoeh.antennapod.core.sync.model.EpisodeAction;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.dialog.ShareDialog;
/**
* Handles interactions with the FeedItemMenu.
@ -61,20 +63,9 @@ public class FeedItemMenuHandler {
}
if (!ShareUtils.hasLinkToShare(selectedItem)) {
setItemVisibility(menu, R.id.visit_website_item, false);
setItemVisibility(menu, R.id.share_link_item, false);
setItemVisibility(menu, R.id.share_link_with_position_item, false);
}
if (!hasMedia || selectedItem.getMedia().getDownload_url() == null) {
setItemVisibility(menu, R.id.share_download_url_item, false);
setItemVisibility(menu, R.id.share_download_url_with_position_item, false);
}
if(!hasMedia || selectedItem.getMedia().getPosition() <= 0) {
setItemVisibility(menu, R.id.share_download_url_with_position_item, false);
setItemVisibility(menu, R.id.share_link_with_position_item, false);
}
boolean fileDownloaded = hasMedia && selectedItem.getMedia().fileExists();
setItemVisibility(menu, R.id.share_file, fileDownloaded);
setItemVisibility(menu, R.id.remove_new_flag_item, selectedItem.isNew());
if (selectedItem.isPlayed()) {
@ -243,20 +234,9 @@ public class FeedItemMenuHandler {
case R.id.visit_website_item:
IntentUtils.openInBrowser(context, FeedItemUtil.getLinkWithFallback(selectedItem));
break;
case R.id.share_link_item:
ShareUtils.shareFeedItemLink(context, selectedItem);
break;
case R.id.share_download_url_item:
ShareUtils.shareFeedItemDownloadLink(context, selectedItem);
break;
case R.id.share_link_with_position_item:
ShareUtils.shareFeedItemLink(context, selectedItem, true);
break;
case R.id.share_download_url_with_position_item:
ShareUtils.shareFeedItemDownloadLink(context, selectedItem, true);
break;
case R.id.share_file:
ShareUtils.shareFeedItemFile(context, selectedItem.getMedia());
case R.id.share_item:
ShareDialog shareDialog = ShareDialog.newInstance(selectedItem);
shareDialog.show((fragment.getActivity().getSupportFragmentManager()), "ShareEpisodeDialog");
break;
default:
Log.d(TAG, "Unknown menuItemId: " + menuItemId);

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="16dp">
<RadioGroup
android:id="@+id/share_dialog_radio_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="vertical">
<RadioButton android:id="@+id/share_episode_website_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/share_dialog_episode_website_label"
android:checked="true"
/>
<RadioButton android:id="@+id/share_media_file_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/share_dialog_media_file_label"
/>
</RadioGroup>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/share_dialog_include_label"/>
<CheckBox
android:id="@+id/share_start_at_timer_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/share_playback_position_dialog_label" />
</LinearLayout>

View File

@ -71,29 +71,7 @@
<item
android:id="@+id/share_item"
android:menuCategory="container"
android:title="@string/share_label">
<menu>
<item
android:id="@+id/share_link_item"
android:menuCategory="container"
android:title="@string/share_link_label" />
<item
android:id="@+id/share_link_with_position_item"
android:menuCategory="container"
android:title="@string/share_link_with_position_label" />
<item
android:id="@+id/share_download_url_item"
android:menuCategory="container"
android:title="@string/share_item_url_label" />
<item
android:id="@+id/share_download_url_with_position_item"
android:menuCategory="container"
android:title="@string/share_item_url_with_position_label" />
<item
android:id="@+id/share_file"
android:menuCategory="container"
android:title="@string/share_file_label" />
</menu>
android:title="@string/share_label_with_ellipses">
</item>
<item

View File

@ -52,19 +52,25 @@
android:title="@string/visit_website_label"
android:visible="true">
</item>
<item
android:id="@+id/share_link_item"
android:id="@+id/share_item"
android:menuCategory="container"
custom:showAsAction="collapseActionView"
android:title="@string/share_website_url_label">
</item>
<item
android:id="@+id/share_download_url_item"
android:menuCategory="container"
custom:showAsAction="collapseActionView"
android:title="@string/share_feed_url_label">
custom:showAsAction="never"
android:title="@string/share_label_with_ellipses">
<menu>
<item
android:id="@+id/share_link_item"
android:title="@string/share_website_url_label">
</item>
<item
android:id="@+id/share_download_url_item"
android:title="@string/share_feed_url_label">
</item>
</menu>
</item>
<item
android:id="@+id/rename_item"
android:menuCategory="container"

View File

@ -62,28 +62,6 @@
android:id="@+id/share_item"
android:menuCategory="container"
custom:showAsAction="never"
android:title="@string/share_label">
<menu>
<item
android:id="@+id/share_link_item"
android:menuCategory="container"
android:title="@string/share_link_label" />
<item
android:id="@+id/share_link_with_position_item"
android:menuCategory="container"
android:title="@string/share_link_with_position_label" />
<item
android:id="@+id/share_download_url_item"
android:menuCategory="container"
android:title="@string/share_item_url_label" />
<item
android:id="@+id/share_download_url_with_position_item"
android:menuCategory="container"
android:title="@string/share_item_url_with_position_label" />
<item
android:id="@+id/share_file"
android:menuCategory="container"
android:title="@string/share_file_label" />
</menu>
android:title="@string/share_label_with_ellipses">
</item>
</menu>

View File

@ -7,6 +7,7 @@ import android.text.TextUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@ -24,7 +25,7 @@ import de.danoeh.antennapod.core.util.ShownotesProvider;
*
* @author daniel
*/
public class FeedItem extends FeedComponent implements ShownotesProvider, ImageResource {
public class FeedItem extends FeedComponent implements ShownotesProvider, ImageResource, Serializable {
/** tag that indicates this item is in the queue */
public static final String TAG_QUEUE = "Queue";

View File

@ -136,12 +136,13 @@
<string name="feed_settings_label">Podcast settings</string>
<string name="rename_feed_label">Rename podcast</string>
<string name="remove_feed_label">Remove podcast</string>
<string name="share_label">Share&#8230;</string>
<string name="share_label">Share</string>
<string name="share_label_with_ellipses">Share…</string>
<string name="share_link_label">Share Episode URL</string>
<string name="share_link_with_position_label">Share Episode URL with Position</string>
<string name="share_file_label">Share File</string>
<string name="share_website_url_label">Share Website URL</string>
<string name="share_feed_url_label">Share Podcast URL</string>
<string name="share_website_url_label">Website address</string>
<string name="share_feed_url_label">Podcast feed URL</string>
<string name="share_item_url_label">Share Media File URL</string>
<string name="share_item_url_with_position_label">Share Media File URL with Position</string>
<string name="feed_delete_confirmation_msg">Please confirm that you want to delete the podcast \"%1$s\" and ALL its episodes (including downloaded episodes).</string>
@ -765,6 +766,12 @@
<string name="rating_later_label">Remind me later</string>
<string name="rating_now_label">Sure, let\'s do this!</string>
<!-- Share episode dialog -->
<string name="share_dialog_include_label">Include:</string>
<string name="share_playback_position_dialog_label">Playback position</string>
<string name="share_dialog_media_file_label">Media file URL</string>
<string name="share_dialog_episode_website_label">Episode webpage</string>
<!-- Audio controls -->
<string name="audio_controls">Audio controls</string>
<string name="playback_speed">Playback Speed</string>