diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java index 4e96f3bb6e5..98b08f61da8 100644 --- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java +++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java @@ -2,6 +2,7 @@ import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO; import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO; +import static org.schabi.newpipe.ktx.ViewUtils.animateRotation; import android.annotation.SuppressLint; import android.app.IntentService; @@ -10,6 +11,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.os.Build; import android.os.Bundle; import android.text.TextUtils; import android.view.ContextThemeWrapper; @@ -17,6 +19,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.LinearLayout; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.Toast; @@ -27,6 +30,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.content.res.AppCompatResources; +import androidx.appcompat.widget.SwitchCompat; import androidx.core.app.NotificationCompat; import androidx.core.app.ServiceCompat; import androidx.core.widget.TextViewCompat; @@ -35,7 +39,6 @@ import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.databinding.ListRadioIconItemBinding; -import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; @@ -329,8 +332,12 @@ private void showDialog(final List choices) { final Context themeWrapperContext = getThemeWrapperContext(); final LayoutInflater inflater = LayoutInflater.from(themeWrapperContext); - final RadioGroup radioGroup = SingleChoiceDialogViewBinding.inflate(getLayoutInflater()) - .list; + final View dialogView = View.inflate( + themeWrapperContext, + R.layout.dialog_share_context, + null); + + final RadioGroup radioGroup = dialogView.findViewById(R.id.player_group); final DialogInterface.OnClickListener dialogButtonsClickListener = (dialog, which) -> { final int indexOfChild = radioGroup.indexOfChild( @@ -347,9 +354,11 @@ private void showDialog(final List choices) { } }; + initAdvancedOptions(dialogView); + alertDialogChoice = new AlertDialog.Builder(themeWrapperContext) .setTitle(R.string.preferred_open_action_share_menu_title) - .setView(radioGroup) + .setView(dialogView) .setCancelable(true) .setNegativeButton(R.string.just_once, dialogButtonsClickListener) .setPositiveButton(R.string.always, dialogButtonsClickListener) @@ -423,6 +432,65 @@ private void showDialog(final List choices) { } } + private void initAdvancedOptions(final View dialogView) { + final SharedPreferences preferences = + PreferenceManager.getDefaultSharedPreferences(this); + + final LinearLayout layoutAdvancedOptionsContent = + dialogView.findViewById(R.id.advanced_options_content); + final SwitchCompat prioritizeEnqueue = dialogView.findViewById(R.id.prioritize_enqueue); + + /* Initialize component states. */ + setVisibilityOfAdvancedOptions( + dialogView, + false, + false + ); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // It's not possible to add secondary text / it would be to much for the small dialog + // -> Use a tooltip (only works on Android 8+/Oreo - API 26+) + prioritizeEnqueue.setTooltipText(getString(R.string.prioritize_enqueue_summary)); + } + prioritizeEnqueue.setChecked( + preferences.getBoolean( + getString(R.string.prioritize_enqueue), + false + ) + ); + + /* Listener for toggling advanced options view. */ + dialogView.findViewById(R.id.layout_toggle_adv) + .setOnClickListener(v -> setVisibilityOfAdvancedOptions( + dialogView, + layoutAdvancedOptionsContent.getVisibility() != View.VISIBLE, + true + ) + ); + + /* Save linked preference when changed. */ + prioritizeEnqueue.setOnCheckedChangeListener((v, checked) -> + preferences.edit() + .putBoolean(getString(R.string.prioritize_enqueue), checked) + .apply() + ); + } + + private void setVisibilityOfAdvancedOptions( + final View dialogView, + final boolean visible, + final boolean doAnimation + ) { + dialogView.findViewById(R.id.advanced_options_content) + .setVisibility(visible ? View.VISIBLE : View.GONE); + + animateRotation( + dialogView.findViewById(R.id.toggle_adv_icon), + doAnimation ? 300 : 0, + visible ? 0 : -90 + ); + } + private List getChoicesForService(final StreamingService service, final LinkType linkType) { final Context context = getThemeWrapperContext(); @@ -796,12 +864,28 @@ public Consumer getResultHandler(final Choice choice) { return; } - if (choice.playerChoice.equals(videoPlayerKey)) { - NavigationHelper.playOnMainPlayer(this, playQueue, false); - } else if (choice.playerChoice.equals(backgroundPlayerKey)) { - NavigationHelper.playOnBackgroundPlayer(this, playQueue, true); - } else if (choice.playerChoice.equals(popupPlayerKey)) { - NavigationHelper.playOnPopupPlayer(this, playQueue, true); + final boolean prioritizeEnqueue = preferences.getBoolean( + getString(R.string.prioritize_enqueue), + false); + + // If prioritize_enqueue is enabled, then enqueue this stream. + // Otherwise, open preferred player instead + if (prioritizeEnqueue) { + MainPlayer.PlayerType playerType = MainPlayer.PlayerType.AUDIO; + if (choice.playerChoice.equals(videoPlayerKey)) { + playerType = MainPlayer.PlayerType.VIDEO; + } else if (choice.playerChoice.equals(popupPlayerKey)) { + playerType = MainPlayer.PlayerType.POPUP; + } // else background, init value of playerType + NavigationHelper.enqueueOnPlayer(this, playQueue, playerType); + } else { + if (choice.playerChoice.equals(videoPlayerKey)) { + NavigationHelper.playOnMainPlayer(this, playQueue, false); + } else if (choice.playerChoice.equals(backgroundPlayerKey)) { + NavigationHelper.playOnBackgroundPlayer(this, playQueue, true); + } else if (choice.playerChoice.equals(popupPlayerKey)) { + NavigationHelper.playOnPopupPlayer(this, playQueue, true); + } } }; } diff --git a/app/src/main/res/layout/dialog_share_context.xml b/app/src/main/res/layout/dialog_share_context.xml new file mode 100644 index 00000000000..c6ae0658750 --- /dev/null +++ b/app/src/main/res/layout/dialog_share_context.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 9489ef543c8..ba7d74a68a2 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -247,6 +247,7 @@ peertube_selected_instance peertube_instance_list content_country + prioritize_enqueue show_age_restricted_content youtube_restricted_mode_enabled enable_search_history diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 897ec0af8b3..3ade96d4958 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -148,6 +148,8 @@ Playing in background Playing in popup mode Content + Prioritize stream queuing + Attempt to enqueue streams for shared URLs instead of playing them immediately Show age restricted content Show content possibly unsuitable for children because it has an age limit (like 18+) Turn on YouTube\'s \"Restricted Mode\" @@ -704,4 +706,5 @@ Error at Show Channel Details Loading Channel Details… + Advanced options diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml index f605fbe170e..55c55735926 100644 --- a/app/src/main/res/xml/video_audio_settings.xml +++ b/app/src/main/res/xml/video_audio_settings.xml @@ -119,6 +119,13 @@ app:singleLineTitle="false" app:iconSpaceReserved="false" /> + +