From 0077794f0f4906adc849b67f50dd560346ac5c2a Mon Sep 17 00:00:00 2001 From: FongMi Date: Mon, 12 Sep 2022 15:07:21 +0800 Subject: [PATCH] Support track selector --- .../tv/ui/activity/DetailActivity.java | 56 ++-- .../leanback/res/layout/activity_detail.xml | 23 +- app/src/leanback/res/layout/adapter_parse.xml | 2 +- app/src/leanback/res/layout/dialog_config.xml | 9 +- .../res/layout/view_controller_bottom.xml | 296 ++++++++++-------- .../res/layout/view_controller_center.xml | 50 --- .../res/layout/view_controller_widget.xml | 112 +++++++ .../android/tv/model/SiteViewModel.java | 2 +- .../com/fongmi/android/tv/player/ExoUtil.java | 5 +- .../tv/ui/custom/TrackSelectionDialog.java | 272 ++++++++++++++++ app/src/main/res/drawable/shape_title.xml | 12 + app/src/main/res/layout/dialog_tracks.xml | 54 ++++ app/src/main/res/layout/view_error.xml | 26 -- app/src/main/res/values-zh-rCN/strings.xml | 2 + app/src/main/res/values-zh-rTW/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + 16 files changed, 664 insertions(+), 261 deletions(-) delete mode 100644 app/src/leanback/res/layout/view_controller_center.xml create mode 100644 app/src/leanback/res/layout/view_controller_widget.xml create mode 100644 app/src/main/java/com/fongmi/android/tv/ui/custom/TrackSelectionDialog.java create mode 100644 app/src/main/res/drawable/shape_title.xml create mode 100644 app/src/main/res/layout/dialog_tracks.xml delete mode 100644 app/src/main/res/layout/view_error.xml diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java index a3336d532..8597b4bbd 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java @@ -38,6 +38,7 @@ import com.fongmi.android.tv.net.OKHttp; import com.fongmi.android.tv.player.ExoUtil; import com.fongmi.android.tv.player.Players; import com.fongmi.android.tv.ui.custom.CustomKeyDown; +import com.fongmi.android.tv.ui.custom.TrackSelectionDialog; import com.fongmi.android.tv.ui.presenter.EpisodePresenter; import com.fongmi.android.tv.ui.presenter.FlagPresenter; import com.fongmi.android.tv.ui.presenter.GroupPresenter; @@ -147,6 +148,7 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen mControl.scale.setOnClickListener(view -> onScale()); mControl.reset.setOnClickListener(view -> onReset()); mControl.speed.setOnClickListener(view -> onSpeed()); + mControl.tracks.setOnClickListener(view -> onTracks()); mControl.ending.setOnClickListener(view -> onEnding()); mControl.opening.setOnClickListener(view -> onOpening()); mControl.interval.setOnClickListener(view -> onInterval()); @@ -212,8 +214,8 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen private void resetFocus(boolean useParse) { mControl.exoProgress.setNextFocusUpId(useParse ? R.id.parse : R.id.next); - for (int i = 0; i < mControl.playLayout.getChildCount(); i++) { - mControl.playLayout.getChildAt(i).setNextFocusDownId(useParse ? R.id.parse : com.google.android.exoplayer2.ui.R.id.exo_progress); + for (int i = 0; i < mControl.actionLayout.getChildCount(); i++) { + mControl.actionLayout.getChildAt(i).setNextFocusDownId(useParse ? R.id.parse : com.google.android.exoplayer2.ui.R.id.exo_progress); } } @@ -224,9 +226,10 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen private void getPlayer(boolean replay) { Vod.Flag.Episode item = (Vod.Flag.Episode) mEpisodeAdapter.get(getEpisodePosition()); if (mFullscreen && Players.get().getRetry() == 0) Notify.show(ResUtil.getString(R.string.play_ready, item.getName())); + mBinding.widget.title.setText(getString(R.string.detail_title, mBinding.name.getText(), item.getName())); mViewModel.playerContent(getKey(), getVodFlag().getFlag(), item.getUrl()); - mBinding.progress.getRoot().setVisibility(View.VISIBLE); - mBinding.error.getRoot().setVisibility(View.GONE); + mBinding.widget.progress.getRoot().setVisibility(View.VISIBLE); + mBinding.widget.error.setVisibility(View.GONE); updateHistory(item, replay); } @@ -272,6 +275,7 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen for (int i = 0; i < mFlagAdapter.size(); i++) ((Vod.Flag) mFlagAdapter.get(i)).toggle(mCurrent == i, item); mEpisodeAdapter.notifyArrayItemRangeChanged(0, mEpisodeAdapter.size()); mHandler.post(() -> mBinding.episode.setSelectedPosition(getEpisodePosition())); + mBinding.widget.title.setText(getString(R.string.detail_title, mBinding.name.getText(), item.getName())); if (mEpisodeAdapter.size() == 0) return; getPlayer(false); } @@ -284,8 +288,8 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen private void setParseActivated(Parse item) { ApiConfig.get().setParse(item); - mBinding.error.getRoot().setVisibility(View.GONE); - mBinding.progress.getRoot().setVisibility(View.VISIBLE); + mBinding.widget.error.setVisibility(View.GONE); + mBinding.widget.progress.getRoot().setVisibility(View.VISIBLE); Result result = mViewModel.getPlayer().getValue(); if (result != null) Players.get().start(result, true); mParseAdapter.notifyArrayItemRangeChanged(0, mParseAdapter.size()); @@ -423,6 +427,12 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen mHistory.update(); } + private void onTracks() { + mHandler.postDelayed(() -> getPlayerView().hideController(), 150); + TrackSelectionDialog.createForPlayer(Players.get().exo(), dialog -> { + }).show(getSupportFragmentManager(), "tracks"); + } + private void getPart(String source) { OKHttp.newCall("http://api.pullword.com/get.php?source=" + URLEncoder.encode(source) + "¶m1=0¶m2=0&json=1").enqueue(new Callback() { @Override @@ -483,8 +493,9 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen private final Runnable mHideCenter = new Runnable() { @Override public void run() { - mBinding.center.action.setImageResource(R.drawable.ic_play); - mBinding.center.getRoot().setVisibility(View.GONE); + mBinding.widget.action.setImageResource(R.drawable.ic_play); + mBinding.widget.center.setVisibility(View.GONE); + mBinding.widget.title.setVisibility(View.GONE); } }; @@ -512,11 +523,12 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen case Player.STATE_IDLE: break; case Player.STATE_BUFFERING: - mBinding.progress.getRoot().setVisibility(View.VISIBLE); + mBinding.widget.progress.getRoot().setVisibility(View.VISIBLE); break; case Player.STATE_READY: Players.get().setRetry(0); - mBinding.progress.getRoot().setVisibility(View.GONE); + TrackSelectionDialog.setVisible(mControl.tracks); + mBinding.widget.progress.getRoot().setVisibility(View.GONE); break; case Player.STATE_ENDED: if (Players.get().canNext()) checkNext(); @@ -548,9 +560,9 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen } private void onError(String msg) { - mBinding.progress.getRoot().setVisibility(View.GONE); - mBinding.error.getRoot().setVisibility(View.VISIBLE); - mBinding.error.text.setText(msg); + mBinding.widget.progress.getRoot().setVisibility(View.GONE); + mBinding.widget.error.setVisibility(View.VISIBLE); + mBinding.widget.text.setText(msg); Players.get().stop(); stopTimer(); } @@ -563,10 +575,10 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen @Override public void onSeeking(int time) { - mBinding.center.exoDuration.setText(mControl.exoDuration.getText()); - mBinding.center.exoPosition.setText(Players.get().getTime(time)); - mBinding.center.action.setImageResource(time > 0 ? R.drawable.ic_forward : R.drawable.ic_rewind); - mBinding.center.getRoot().setVisibility(View.VISIBLE); + mBinding.widget.exoDuration.setText(mControl.exoDuration.getText()); + mBinding.widget.exoPosition.setText(Players.get().getTime(time)); + mBinding.widget.action.setImageResource(time > 0 ? R.drawable.ic_forward : R.drawable.ic_rewind); + mBinding.widget.center.setVisibility(View.VISIBLE); } @Override @@ -587,12 +599,14 @@ public class DetailActivity extends BaseActivity implements CustomKeyDown.Listen public void onKeyCenter() { if (Players.get().isPlaying()) { Players.get().pause(); - mBinding.center.getRoot().setVisibility(View.VISIBLE); - mBinding.center.exoPosition.setText(Players.get().getTime(0)); - mBinding.center.exoDuration.setText(mControl.exoDuration.getText()); + mBinding.widget.title.setVisibility(View.VISIBLE); + mBinding.widget.center.setVisibility(View.VISIBLE); + mBinding.widget.exoPosition.setText(Players.get().getTime(0)); + mBinding.widget.exoDuration.setText(mControl.exoDuration.getText()); } else { Players.get().play(); - mBinding.center.getRoot().setVisibility(View.GONE); + mBinding.widget.title.setVisibility(View.GONE); + mBinding.widget.center.setVisibility(View.GONE); } } diff --git a/app/src/leanback/res/layout/activity_detail.xml b/app/src/leanback/res/layout/activity_detail.xml index d0b0fe869..69436dc46 100644 --- a/app/src/leanback/res/layout/activity_detail.xml +++ b/app/src/leanback/res/layout/activity_detail.xml @@ -43,25 +43,10 @@ app:use_controller="false" /> - - - - + android:id="@+id/widget" + layout="@layout/view_controller_widget" + android:layout_width="match_parent" + android:layout_height="match_parent" /> diff --git a/app/src/leanback/res/layout/adapter_parse.xml b/app/src/leanback/res/layout/adapter_parse.xml index cf858a378..03af7be12 100644 --- a/app/src/leanback/res/layout/adapter_parse.xml +++ b/app/src/leanback/res/layout/adapter_parse.xml @@ -8,7 +8,7 @@ android:focusable="true" android:focusableInTouchMode="true" android:gravity="center" - android:nextFocusUp="@id/playLayout" + android:nextFocusUp="@id/action" android:nextFocusDown="@id/exo_progress" android:singleLine="true" android:textColor="@color/white" diff --git a/app/src/leanback/res/layout/dialog_config.xml b/app/src/leanback/res/layout/dialog_config.xml index 04af8fb04..e577d1037 100644 --- a/app/src/leanback/res/layout/dialog_config.xml +++ b/app/src/leanback/res/layout/dialog_config.xml @@ -35,6 +35,7 @@ android:imeOptions="actionDone" android:importantForAutofill="no" android:inputType="text" + android:nextFocusDown="@id/positive" android:singleLine="true" android:textSize="18sp" /> @@ -47,7 +48,7 @@ android:orientation="horizontal"> diff --git a/app/src/leanback/res/layout/view_controller_bottom.xml b/app/src/leanback/res/layout/view_controller_bottom.xml index fbb7b4f80..81f9db5f5 100644 --- a/app/src/leanback/res/layout/view_controller_bottom.xml +++ b/app/src/leanback/res/layout/view_controller_bottom.xml @@ -15,148 +15,170 @@ android:paddingEnd="16dp" android:paddingBottom="8dp"> - - - - - - - - - - - - - - - + android:fillViewport="true" + android:scrollbars="none"> - - - - - - - - - + android:animateLayoutChanges="true" + android:gravity="center_vertical" + android:orientation="horizontal"> + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/leanback/res/layout/view_controller_widget.xml b/app/src/leanback/res/layout/view_controller_widget.xml new file mode 100644 index 000000000..42c68cdba --- /dev/null +++ b/app/src/leanback/res/layout/view_controller_widget.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java index 6ed6851c3..318942536 100644 --- a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java +++ b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java @@ -164,7 +164,7 @@ public class SiteViewModel extends ViewModel { if (site.getType() == 1) params.put("ac", "detail"); params.put("wd", keyword); String body = OKHttp.newCall(site.getApi(), params).execute().body().string(); - SpiderDebug.log(site.getName() +"," +body); + SpiderDebug.log(site.getName() + "," + body); if (site.getType() == 0) post(site, Result.fromXml(body)); else post(site, Result.fromJson(body)); } diff --git a/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java b/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java index c8010a35c..9ae06e855 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java +++ b/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java @@ -13,6 +13,7 @@ import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.ext.rtmp.RtmpDataSource; import com.google.android.exoplayer2.source.DefaultMediaSourceFactory; import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.ui.CaptionStyleCompat; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultDataSource; @@ -28,7 +29,7 @@ public class ExoUtil { static ExoPlayer create() { DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(App.get()); renderersFactory.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER); - return new ExoPlayer.Builder(App.get()).setRenderersFactory(renderersFactory).build(); + return new ExoPlayer.Builder(App.get()).setRenderersFactory(renderersFactory).setTrackSelector(new DefaultTrackSelector(App.get())).build(); } public static CaptionStyleCompat getCaptionStyle() { @@ -54,7 +55,7 @@ public class ExoUtil { } private static MediaItem.SubtitleConfiguration getConfig(Result result) { - return result.getSub().isEmpty() ? null : new MediaItem.SubtitleConfiguration.Builder(Uri.parse(result.getSub())).setMimeType(MimeTypes.APPLICATION_SUBRIP).setSelectionFlags(C.SELECTION_FLAG_DEFAULT).build(); + return result.getSub().isEmpty() ? null : new MediaItem.SubtitleConfiguration.Builder(Uri.parse(result.getSub())).setLabel("Spider").setMimeType(MimeTypes.APPLICATION_SUBRIP).setSelectionFlags(C.SELECTION_FLAG_DEFAULT).build(); } private static DataSource.Factory getFactory(Map headers, String url) { diff --git a/app/src/main/java/com/fongmi/android/tv/ui/custom/TrackSelectionDialog.java b/app/src/main/java/com/fongmi/android/tv/ui/custom/TrackSelectionDialog.java new file mode 100644 index 000000000..9fb0be7e6 --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/ui/custom/TrackSelectionDialog.java @@ -0,0 +1,272 @@ +package com.fongmi.android.tv.ui.custom; + +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.os.Bundle; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatDialog; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import com.fongmi.android.tv.player.Players; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.Tracks; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.trackselection.TrackSelectionOverride; +import com.google.android.exoplayer2.trackselection.TrackSelectionParameters; +import com.google.android.exoplayer2.ui.R; +import com.google.android.exoplayer2.ui.TrackSelectionView; +import com.google.android.material.tabs.TabLayout; +import com.google.common.collect.ImmutableList; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class TrackSelectionDialog extends DialogFragment { + + public static final ImmutableList SUPPORTED_TRACK_TYPES = ImmutableList.of(C.TRACK_TYPE_VIDEO, C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_TEXT); + private final SparseArray tabFragments; + private final ArrayList tabTrackTypes; + private DialogInterface.OnClickListener onClickListener; + private DialogInterface.OnDismissListener onDismissListener; + + public TrackSelectionDialog() { + tabFragments = new SparseArray<>(); + tabTrackTypes = new ArrayList<>(); + setRetainInstance(true); + } + + /** + * Returns whether a track selection dialog will have content to display if initialized with the + * specified {@link Player}. + */ + public static void setVisible(View view) { + view.setVisibility(willHaveContent(Players.get().exo().getCurrentTracks()) ? View.VISIBLE : View.GONE); + } + + /** + * Returns whether a track selection dialog will have content to display if initialized with the + * specified {@link Tracks}. + */ + public static boolean willHaveContent(Tracks tracks) { + for (Tracks.Group trackGroup : tracks.getGroups()) { + if (SUPPORTED_TRACK_TYPES.contains(trackGroup.getType())) { + return true; + } + } + return false; + } + + /** + * Creates a dialog for a given {@link Player}, whose parameters will be automatically updated + * when tracks are selected. + * + * @param player The {@link Player}. + * @param onDismissListener A {@link DialogInterface.OnDismissListener} to call when the dialog is + * dismissed. + */ + public static TrackSelectionDialog createForPlayer(Player player, DialogInterface.OnDismissListener onDismissListener) { + return createForTracksAndParameters(player.getCurrentTracks(), player.getTrackSelectionParameters(), true, false, player::setTrackSelectionParameters, onDismissListener); + } + + /** + * Creates a dialog for given {@link Tracks} and {@link TrackSelectionParameters}. + * + * @param tracks The {@link Tracks} describing the tracks to display. + * @param trackSelectionParameters The initial {@link TrackSelectionParameters}. + * @param allowAdaptiveSelections Whether adaptive selections (consisting of more than one track) + * can be made. + * @param allowMultipleOverrides Whether tracks from multiple track groups can be selected. + * @param trackSelectionListener Called when tracks are selected. + * @param onDismissListener {@link DialogInterface.OnDismissListener} called when the dialog is + * dismissed. + */ + public static TrackSelectionDialog createForTracksAndParameters(Tracks tracks, TrackSelectionParameters trackSelectionParameters, boolean allowAdaptiveSelections, boolean allowMultipleOverrides, TrackSelectionListener trackSelectionListener, DialogInterface.OnDismissListener onDismissListener) { + TrackSelectionDialog trackSelectionDialog = new TrackSelectionDialog(); + trackSelectionDialog.init(tracks, trackSelectionParameters, allowAdaptiveSelections, allowMultipleOverrides, (dialog, which) -> { + TrackSelectionParameters.Builder builder = trackSelectionParameters.buildUpon(); + for (int i = 0; i < SUPPORTED_TRACK_TYPES.size(); i++) { + int trackType = SUPPORTED_TRACK_TYPES.get(i); + builder.setTrackTypeDisabled(trackType, trackSelectionDialog.getIsDisabled(trackType)); + builder.clearOverridesOfType(trackType); + Map overrides = trackSelectionDialog.getOverrides(trackType); + for (TrackSelectionOverride override : overrides.values()) builder.addOverride(override); + } + trackSelectionListener.onTracksSelected(builder.build()); + }, onDismissListener); + return trackSelectionDialog; + } + + private static String getTrackTypeString(Resources resources, @C.TrackType int trackType) { + switch (trackType) { + case C.TRACK_TYPE_VIDEO: + return resources.getString(R.string.exo_track_selection_title_video); + case C.TRACK_TYPE_AUDIO: + return resources.getString(R.string.exo_track_selection_title_audio); + case C.TRACK_TYPE_TEXT: + return resources.getString(R.string.exo_track_selection_title_text); + default: + throw new IllegalArgumentException(); + } + } + + private void init(Tracks tracks, TrackSelectionParameters trackSelectionParameters, boolean allowAdaptiveSelections, boolean allowMultipleOverrides, DialogInterface.OnClickListener onClickListener, DialogInterface.OnDismissListener onDismissListener) { + this.onClickListener = onClickListener; + this.onDismissListener = onDismissListener; + for (int i = 0; i < SUPPORTED_TRACK_TYPES.size(); i++) { + @C.TrackType int trackType = SUPPORTED_TRACK_TYPES.get(i); + ArrayList trackGroups = new ArrayList<>(); + for (Tracks.Group trackGroup : tracks.getGroups()) { + if (trackGroup.getType() == trackType) { + trackGroups.add(trackGroup); + } + } + if (!trackGroups.isEmpty()) { + TrackSelectionViewFragment tabFragment = new TrackSelectionViewFragment(); + tabFragment.init(trackGroups, trackSelectionParameters.disabledTrackTypes.contains(trackType), trackSelectionParameters.overrides, allowAdaptiveSelections, allowMultipleOverrides); + tabFragments.put(trackType, tabFragment); + tabTrackTypes.add(trackType); + } + } + } + + /** + * Returns whether the disabled option is selected for the specified track type. + * + * @param trackType The track type. + * @return Whether the disabled option is selected for the track type. + */ + public boolean getIsDisabled(int trackType) { + TrackSelectionViewFragment trackView = tabFragments.get(trackType); + return trackView != null && trackView.isDisabled; + } + + /** + * Returns the selected track overrides for the specified track type. + * + * @param trackType The track type. + * @return The track overrides for the track type. + */ + public Map getOverrides(int trackType) { + TrackSelectionViewFragment trackView = tabFragments.get(trackType); + return trackView == null ? Collections.emptyMap() : trackView.overrides; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Dialog dialog = new AppCompatDialog(getActivity()); + dialog.getWindow().setDimAmount(0); + return dialog; + } + + @Override + public void onDismiss(@NonNull DialogInterface dialog) { + super.onDismiss(dialog); + onDismissListener.onDismiss(dialog); + } + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View dialogView = inflater.inflate(com.fongmi.android.tv.R.layout.dialog_tracks, container, false); + TabLayout tabLayout = dialogView.findViewById(com.fongmi.android.tv.R.id.track_selection_dialog_tab_layout); + ViewPager viewPager = dialogView.findViewById(com.fongmi.android.tv.R.id.track_selection_dialog_view_pager); + TextView cancelButton = dialogView.findViewById(com.fongmi.android.tv.R.id.track_selection_dialog_cancel_button); + TextView okButton = dialogView.findViewById(com.fongmi.android.tv.R.id.track_selection_dialog_ok_button); + viewPager.setAdapter(new FragmentAdapter(getChildFragmentManager())); + tabLayout.setupWithViewPager(viewPager); + tabLayout.setVisibility(tabFragments.size() > 1 ? View.VISIBLE : View.GONE); + cancelButton.setOnClickListener(view -> dismiss()); + okButton.setOnClickListener(view -> { + onClickListener.onClick(getDialog(), DialogInterface.BUTTON_POSITIVE); + dismiss(); + }); + return dialogView; + } + + public interface TrackSelectionListener { + + void onTracksSelected(TrackSelectionParameters trackSelectionParameters); + } + + /** + * Fragment to show a track selection in tab of the track selection dialog. + */ + public static final class TrackSelectionViewFragment extends Fragment implements TrackSelectionView.TrackSelectionListener { + + private List trackGroups; + private boolean allowAdaptiveSelections; + private boolean allowMultipleOverrides; + Map overrides; + boolean isDisabled; + + public TrackSelectionViewFragment() { + setRetainInstance(true); + } + + public void init(List trackGroups, boolean isDisabled, Map overrides, boolean allowAdaptiveSelections, boolean allowMultipleOverrides) { + this.trackGroups = trackGroups; + this.isDisabled = isDisabled; + this.allowAdaptiveSelections = allowAdaptiveSelections; + this.allowMultipleOverrides = allowMultipleOverrides; + // TrackSelectionView does this filtering internally, but we need to do it here as well to + // handle the case where the TrackSelectionView is never created. + this.overrides = new HashMap<>(TrackSelectionView.filterOverrides(overrides, trackGroups, allowMultipleOverrides)); + } + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.exo_track_selection_dialog, container, /* attachToRoot= */ false); + TrackSelectionView trackSelectionView = rootView.findViewById(R.id.exo_track_selection_view); + trackSelectionView.setShowDisableOption(true); + trackSelectionView.setAllowMultipleOverrides(allowMultipleOverrides); + trackSelectionView.setAllowAdaptiveSelections(allowAdaptiveSelections); + trackSelectionView.init(trackGroups, isDisabled, overrides, null, this); + return rootView; + } + + @Override + public void onTrackSelectionChanged(boolean isDisabled, @NonNull Map overrides) { + this.isDisabled = isDisabled; + this.overrides = overrides; + } + } + + private final class FragmentAdapter extends FragmentPagerAdapter { + + public FragmentAdapter(FragmentManager fragmentManager) { + super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + } + + @NonNull + @Override + public Fragment getItem(int position) { + return tabFragments.get(tabTrackTypes.get(position)); + } + + @Override + public int getCount() { + return tabTrackTypes.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return getTrackTypeString(getResources(), tabTrackTypes.get(position)); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_title.xml b/app/src/main/res/drawable/shape_title.xml new file mode 100644 index 000000000..54bd9fd1b --- /dev/null +++ b/app/src/main/res/drawable/shape_title.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_tracks.xml b/app/src/main/res/layout/dialog_tracks.xml new file mode 100644 index 000000000..4c14b4cd3 --- /dev/null +++ b/app/src/main/res/layout/dialog_tracks.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_error.xml b/app/src/main/res/layout/view_error.xml deleted file mode 100644 index 565d4505a..000000000 --- a/app/src/main/res/layout/view_error.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 5ba84b486..dea46ef31 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -11,6 +11,7 @@ 上次看到%s + %s%s 站源:%s 年份:%s 地区:%s @@ -26,6 +27,7 @@ 准备播放:%s 重播 重置 + 轨道 片头片尾 倒序 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 2122cb255..cd5886e97 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -11,6 +11,7 @@ 上次看到%s + %s%s 站源:%s 年份:%s 地區:%s @@ -26,6 +27,7 @@ 準備播放:%s 重播 重置 + 軌道 片頭片尾 倒序 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1e9698aa9..5303ea962 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,6 +11,7 @@ Last seen %s + %s : %s Site: %s Year: %s Area: %s @@ -26,6 +27,7 @@ Ready to play: %s Replay Reset + Tracks OP&ED Reverse